Java >> Java tutorial >  >> Tag >> java.net

Registrering og brug af en brugerdefineret java.net.URL-protokol

  1. Opret en tilpasset URLConnection implementering, som udfører jobbet i connect() metode.

    public class CustomURLConnection extends URLConnection {
    
        protected CustomURLConnection(URL url) {
            super(url);
        }
    
        @Override
        public void connect() throws IOException {
            // Do your job here. As of now it merely prints "Connected!".
            System.out.println("Connected!");
        }
    
    }
    

    Glem ikke at tilsidesætte og implementere andre metoder såsom getInputStream() derfor. Flere detaljer om det kan ikke gives, da disse oplysninger mangler i spørgsmålet.

  2. Opret en tilpasset URLStreamHandler implementering, som returnerer den i openConnection() .

    public class CustomURLStreamHandler extends URLStreamHandler {
    
        @Override
        protected URLConnection openConnection(URL url) throws IOException {
            return new CustomURLConnection(url);
        }
    
    }
    

    Glem ikke at tilsidesætte og implementere andre metoder, hvis det er nødvendigt.

  3. Opret en tilpasset URLStreamHandlerFactory som opretter og returnerer det baseret på protokollen.

    public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
    
        @Override
        public URLStreamHandler createURLStreamHandler(String protocol) {
            if ("customuri".equals(protocol)) {
                return new CustomURLStreamHandler();
            }
    
            return null;
        }
    
    }
    

    Bemærk, at protokoller altid er små bogstaver.

  4. Til sidst registrer det under applikationens opstart via URL#setURLStreamHandlerFactory()

    URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
    

    Bemærk, at Javadoc udtrykkeligt siger, at du højst kan indstille det én gang. Så hvis du har til hensigt at understøtte flere brugerdefinerede protokoller i samme applikation, skal du generere den tilpassede URLStreamHandlerFactory implementering for at dække dem alle inde i createURLStreamHandler() metode.

    Alternativt, hvis du ikke kan lide Demeterloven, så smid det hele sammen i anonyme klasser til kodeminificering:

    URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
        public URLStreamHandler createURLStreamHandler(String protocol) {
            return "customuri".equals(protocol) ? new URLStreamHandler() {
                protected URLConnection openConnection(URL url) throws IOException {
                    return new URLConnection(url) {
                        public void connect() throws IOException {
                            System.out.println("Connected!");
                        }
                    };
                }
            } : null;
        }
    });
    

    Hvis du allerede er på Java 8, skal du erstatte URLStreamHandlerFactory funktionel grænseflade med en lambda for yderligere minifikation:

    URL.setURLStreamHandlerFactory(protocol -> "customuri".equals(protocol) ? new URLStreamHandler() {
        protected URLConnection openConnection(URL url) throws IOException {
            return new URLConnection(url) {
                public void connect() throws IOException {
                    System.out.println("Connected!");
                }
            };
        }
    } : null);
    

Nu kan du bruge det som følger:

URLConnection connection = new URL("CustomURI:blabla").openConnection();
connection.connect();
// ...

Eller med små bogstaver i overensstemmelse med specifikationerne:

URLConnection connection = new URL("customuri:blabla").openConnection();
connection.connect();
// ...

Hvis du ikke ønsker at overtage den ene-og-kun URLStreamHandlerFactory, kan du faktisk bruge en hæslig, men effektiv navnekonvention til at komme ind på standardimplementeringen.

Du skal navngiv din URLStreamHandler klasse Handler , og den protokol, den er knyttet til, er det sidste segment af den klasses pakke.

com.foo.myproto.Handler ->myproto:urls , forudsat at du tilføjer din pakke com.foo til listen over "url stream source-pakker" til opslag på ukendt protokol. Du gør dette via systemegenskaben "java.protocol.handler.pkgs" (som er en | separeret liste over pakkenavne, der skal søges i).

Her er en abstrakt klasse, der udfører det, du har brug for:(ikke noget imod den manglende StringTo<Out1<String>> eller StringURLConnection , disse gør, hvad deres navne antyder, og du kan bruge de abstraktioner, du foretrækker)

public abstract class AbstractURLStreamHandler extends URLStreamHandler {

    protected abstract StringTo<Out1<String>> dynamicFiles();

    protected static void addMyPackage(Class<? extends URLStreamHandler> handlerClass) {
        // Ensure that we are registered as a url protocol handler for JavaFxCss:/path css files.
        String was = System.getProperty("java.protocol.handler.pkgs", "");
        String pkg = handlerClass.getPackage().getName();
        int ind = pkg.lastIndexOf('.');
        assert ind != -1 : "You can't add url handlers in the base package";
        assert "Handler".equals(handlerClass.getSimpleName()) : "A URLStreamHandler must be in a class named Handler; not " + handlerClass.getSimpleName();

        System.setProperty("java.protocol.handler.pkgs", handlerClass.getPackage().getName().substring(0, ind) +
            (was.isEmpty() ? "" : "|" + was ));
    }


    @Override
    protected URLConnection openConnection(URL u) throws IOException {
        final String path = u.getPath();
        final Out1<String> file = dynamicFiles().get(path);
        return new StringURLConnection(u, file);
    }
}

Så her er den faktiske klasse, der implementerer abstraktbehandleren (for dynamic: webadresser:

package xapi.dev.api.dynamic;

// imports elided for brevity

public class Handler extends AbstractURLStreamHandler {

    private static final StringTo<Out1<String>> dynamicFiles = X_Collect.newStringMap(Out1.class,
        CollectionOptions.asConcurrent(true)
            .mutable(true)
            .insertionOrdered(false)
            .build());

    static {
        addMyPackage(Handler.class);
    }

    @Override
    protected StringTo<Out1<String>> dynamicFiles() {
        return dynamicFiles;
    }

    public static String registerDynamicUrl(String path, Out1<String> contents) {
        dynamicFiles.put(path, contents);
        return path;
    }

    public static void clearDynamicUrl(String path) {
        dynamicFiles.remove(path);
    }

}

Java tag