001package ball.upnp;
002/*-
003 * ##########################################################################
004 * UPnP/SSDP Implementation Classes
005 * $Id: SSDP.java 7215 2021-01-03 18:39:51Z ball $
006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-upnp/trunk/src/main/java/ball/upnp/SSDP.java $
007 * %%
008 * Copyright (C) 2013 - 2021 Allen D. Ball
009 * %%
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 *
014 *      http://www.apache.org/licenses/LICENSE-2.0
015 *
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 * ##########################################################################
022 */
023import java.net.URI;
024import java.util.Map;
025import java.util.Set;
026import java.util.function.Predicate;
027
028import static ball.upnp.ssdp.SSDPMessage.SSDP_ALL;
029
030/**
031 * SSDP "discoverable" marker interface.
032 *
033 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
034 * @version $Revision: 7215 $
035 */
036public interface SSDP {
037
038    /**
039     * Method to provide the {@link Map} of {@code USN} to {@code NT}
040     * ({@code ST}) permutations required for {@code NOTIFY("ssdp:alive")}
041     * and {@code NOTIFY("ssdp:byebye")} requests and
042     * {@code M-SEARCH("ssdp:all")} responses for {@link.this}
043     * {@link Device} or {@link Service}.
044     *
045     * @return  {@link Map} of {@code USN}/{@code NT} permutations.
046     */
047    public Map<URI,Set<URI>> getUSNMap();
048
049    /**
050     * Method to get the {@code USN} for this {@link Device}
051     * {@code UDN}.
052     *
053     * @param   urn             The {@code URN} {@link URI}.
054     *
055     * @return  The {@code USN} {@link URI}.
056     */
057    public URI getUSN(URI urn);
058
059    /**
060     * Method to test if a {@code NT} satisfies an {@code ST}.
061     *
062     * @param   st              The {@code ST} header value.
063     * @param   nt              The {@code NT} header value.
064     *
065     * @return  {@code true} if {@code nt} satisfies {@code st};
066     *          {@code false} otherwise.
067     */
068    public static boolean matches(URI st, URI nt) {
069        boolean matches =
070            SSDP_ALL.equals(st)
071            || st.toString().equalsIgnoreCase(nt.toString());
072
073        if (! matches) {
074            try {
075                if (! matches) {
076                    if (st.getScheme().equalsIgnoreCase("uuid")) {
077                        matches |=
078                            st.toString().equalsIgnoreCase(nt.toString());
079                    }
080                }
081
082                if (! matches) {
083                    if (st.getScheme().equalsIgnoreCase("urn")) {
084                        /*
085                         * TBD: Create a real SSDP URN parser.
086                         */
087                        String string = st.toString().toUpperCase();
088                        int index = string.lastIndexOf(":");
089
090                        if (index != -1) {
091                            index += 1;
092
093                            String prefix = string.substring(0, index);
094                            String stVersion = string.replace(prefix, "");
095                            String ntVersion =
096                                nt.toString().toUpperCase()
097                                .replace(prefix, "");
098
099                            if (stVersion.matches("[0-9]+") && ntVersion.matches("[0-9]+")) {
100                                matches |=
101                                    Integer.decode(stVersion) <= Integer.decode(ntVersion);
102                            }
103                        }
104                    }
105                }
106            } catch (Exception exception) {
107            }
108        }
109
110        return matches;
111    }
112
113    /**
114     * Method to provide a {@link Predicate} that implements
115     * {@link #matches(URI,URI)}
116     *
117     * @param   st              The {@code ST} header value.
118     *
119     * @return  {@link Predicate} to test if {@code nt} against {@code st}.
120     */
121    public static Predicate<URI> matches(URI st) {
122        return t -> matches(st, t);
123    }
124}