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