/* Copyright (c) 2011 Danish Maritime Authority. * * 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 net.maritimecloud.mms.server.endpoints; import static java.util.Objects.requireNonNull; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import net.maritimecloud.internal.mms.messages.services.AbstractServices; import net.maritimecloud.mms.server.connection.client.Client; import net.maritimecloud.mms.server.connection.client.ClientManager; import net.maritimecloud.mms.server.connection.client.Session; import net.maritimecloud.net.MessageHeader; import net.maritimecloud.util.geometry.Area; import net.maritimecloud.util.geometry.Position; import net.maritimecloud.util.geometry.PositionTime; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; /** * Manages services for all connected targets. * * @author Kasper Nielsen */ public class ServerServices extends AbstractServices { final ClientManager clientManager; // Metrics final Meter endpointRegistrationsMeter; final Meter serviceLocatesMeter; public ServerServices(ClientManager clientManager, MetricRegistry metrics) { this.clientManager = requireNonNull(clientManager); endpointRegistrationsMeter = metrics.meter("endpointRegistrations"); serviceLocatesMeter = metrics.meter("serviceLocates"); } /** * Finds services in proximity to the specified target. * * @param target * the target that is trying to find the service * @return a sorted list of the targets that was found sorted by distance to the target doing the search */ List<Entry<Client, PositionTime>> findServices(Client target, String endpointName, Position pos, double m, int max) { double meters = m <= 0 ? Double.MAX_VALUE : m; final ConcurrentHashMap<Client, PositionTime> map = new ConcurrentHashMap<>(); if (pos == null) { clientManager.forEachTarget(tt -> { if (tt.getEndpointManager().hasService(endpointName)) { map.put(tt, tt.getLatestPositionAndTime()); } }); } else { // Find all services with the area clientManager.forEachTarget(tt -> { if (tt.getEndpointManager().hasService(endpointName)) { PositionTime pt = tt.getLatestPositionAndTime(); if (pt.geodesicDistanceTo(pos) <= meters) { map.put(tt, pt); } } }); } // We remove ourself map.remove(target); // Sort by distance List<Entry<Client, PositionTime>> l = new ArrayList<>(map.entrySet()); if (pos != null) { Collections.sort( l, (o1, o2) -> Double.compare(o1.getValue().geodesicDistanceTo(pos), o2.getValue().geodesicDistanceTo(pos))); } // If we have a maximum number of results, filter the list if (l.size() > max) { l = new ArrayList<>(l.subList(0, max)); } return l; } /** {@inheritDoc} */ @Override protected List<String> locate(MessageHeader header, String endpointName, Integer meters, Integer max) { Session con = ServerEndpointManager.connection(header); List<Entry<Client, PositionTime>> findService = findServices(con.getClient(), endpointName, header.getSenderPosition(), meters, max); List<String> result = new ArrayList<>(); for (Entry<Client, PositionTime> e : findService) { result.add(e.getKey().getId().toString()); } // Update metrics serviceLocatesMeter.mark(); return result; } /** {@inheritDoc} */ @Override protected void registerEndpoint(MessageHeader header, String endpointName) { Session con = ServerEndpointManager.connection(header); ServerClientEndpointManager services = con.getClient().getEndpointManager(); services.registerEndpoint(endpointName); // Update metrics endpointRegistrationsMeter.mark(); } /** {@inheritDoc} */ @Override protected void subscribe(MessageHeader header, List<String> name, Area area) {} /** {@inheritDoc} */ @Override protected void unregisterEndpoint(MessageHeader header, String endpointName) {} }