net.yatomiya.nicherry.services.bbs.BBSHttpClient.java Source code

Java tutorial

Introduction

Here is the source code for net.yatomiya.nicherry.services.bbs.BBSHttpClient.java

Source

/*******************************************************************************
 * Copyright (c) 2014,2015 Hideki Yatomi
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package net.yatomiya.nicherry.services.bbs;

import java.io.*;
import java.net.*;
import java.util.*;
import org.eclipse.e4.core.contexts.*;
import com.squareup.okhttp.*;
import com.squareup.okhttp.Authenticator;
import net.yatomiya.e4.services.*;
import net.yatomiya.e4.util.*;
import net.yatomiya.nicherry.*;
import net.yatomiya.nicherry.model.bbs.*;

public class BBSHttpClient extends StandardHttpClient {
    private IEclipseContext context;
    private CookieManager cookieManager;
    private String proxyCredentials;
    private AccessIntervalInterceptor intervalInterceptor;

    BBSHttpClient(IEclipseContext context) {
        super();

        this.context = context;

        //        setRetryOnConnectionFailure(false);
        //        setFollowRedirects(false);
        //        setFollowSslRedirects(false);

        getDispatcher().setMaxRequestsPerHost(1);

        cookieManager = context.get(PersistenceService.class).get(
                BBSHttpClient.class.getName() + "." + CookieManager.class.getName(), () -> new CookieManager());
        setCookieHandler(cookieManager);

        setAuthenticator(new Authenticator() {
            @Override
            public Request authenticate(Proxy proxy, Response response) throws IOException {
                return null;
            }

            @Override
            public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
                if (getProxy() != null && proxyCredentials != null) {
                    if (!proxyCredentials.equals(response.request().header("Proxy-Authorization"))) {
                        return response.request().newBuilder().header("Proxy-Authorization", proxyCredentials)
                                .build();
                    }
                }

                return null;
            }
        });

        intervalInterceptor = new AccessIntervalInterceptor();

        interceptors().add((chain) -> interceptRequest(chain));
        interceptors().add((chain) -> interceptGetDat(chain));

        {
            PreferenceService prefs = context.get(PreferenceService.class);
            prefs.subscribe(this, NPreferences.NODE, NPreferences.NETWORK_PROXY_ENABLE,
                    event -> applyProxyPreference());
            prefs.subscribe(this, NPreferences.NODE, NPreferences.NETWORK_PROXY_HOST,
                    event -> applyProxyPreference());
            prefs.subscribe(this, NPreferences.NODE, NPreferences.NETWORK_PROXY_PORT,
                    event -> applyProxyPreference());
            prefs.subscribe(this, NPreferences.NODE, NPreferences.NETWORK_PROXY_BASIC_USERNAME,
                    event -> applyProxyPreference());
            prefs.subscribe(this, NPreferences.NODE, NPreferences.NETWORK_PROXY_BASIC_PASSWORD,
                    event -> applyProxyPreference());
            prefs.subscribe(this, NPreferences.NODE, NPreferences.BBS_NETWORK_CONNECT_INTERVAL_PER_HOST,
                    event -> intervalInterceptor.interval = Integer.valueOf(event.getValue()));
        }
    }

    void shutdown() {
        cancelAll();

        context.get(PreferenceService.class).unsubscribe(this);
    }

    @Override
    public Call execute(Request request, Callback callback, boolean isSynchronous) {
        Call call = newCall(request);
        if (isSynchronous) {
            try {
                Response response = call.execute();
                callback.onResponse(response);
            } catch (IOException e) {
                callback.onFailure(request, e);
            }
        } else {
            call.enqueue(callback);
        }
        return call;
    }

    public void clearCookies() {
        cookieManager.getCookieStore().removeAll();
    }

    @Override
    public OkHttpClient clone() {
        throw new UnsupportedOperationException();
    }

    void applyProxyPreference() {
        PreferenceService prefs = context.get(PreferenceService.class);
        boolean enable = Boolean.valueOf(prefs.getString(NPreferences.NODE, NPreferences.NETWORK_PROXY_ENABLE));
        String host = prefs.getString(NPreferences.NODE, NPreferences.NETWORK_PROXY_HOST);
        int port = Integer.valueOf(prefs.getString(NPreferences.NODE, NPreferences.NETWORK_PROXY_PORT));
        String username = prefs.getString(NPreferences.NODE, NPreferences.NETWORK_PROXY_BASIC_USERNAME);
        String password = prefs.getString(NPreferences.NODE, NPreferences.NETWORK_PROXY_BASIC_PASSWORD);

        if (enable && !JUtils.isEmpty(host)) {
            setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)));
        } else {
            setProxy(Proxy.NO_PROXY);
        }

        if (enable && !JUtils.isEmpty(username) && !JUtils.isEmpty(password)) {
            proxyCredentials = Credentials.basic(username, password);
        } else {
            proxyCredentials = null;
        }
    }

    Response interceptRequest(Interceptor.Chain chain) throws IOException {
        Request.Builder builder = chain.request().newBuilder();
        builder.header("User-Agent", NUtils.getPreference(NPreferences.NETWORK_HTTP_USER_AGENT));

        intervalInterceptor.waitInterval(chain.request());

        return chain.proceed(builder.build());
    }

    Response interceptGetDat(Interceptor.Chain chain) throws IOException {
        Object tag = chain.request().tag();
        ThreadUpdateHandler handler = null;
        if ((tag != null) && (tag instanceof ThreadUpdateHandler))
            handler = (ThreadUpdateHandler) tag;

        if (handler == null) {
            return chain.proceed(chain.request());
        } else {
            MThread thread = handler.getModel();
            return ((ThreadUpdateHandler) thread.getProcessor().getUpdateHandler()).processIntercept(chain);
        }
    }

    class AccessIntervalInterceptor {
        int interval = 0;

        class HostData {
            String host;
            long lastAccessTime = -1;
        }

        Map<String, HostData> dataMap = new HashMap<>();

        public void waitInterval(Request request) {
            String host = request.url().getHost();
            HostData data;
            synchronized (this) {
                data = dataMap.get(host);
                if (data == null) {
                    data = new HostData();
                    data.host = host;

                    dataMap.put(host, data);
                }
            }
            synchronized (data) {
                long current = System.currentTimeMillis();
                if (data.lastAccessTime >= 0) {
                    long elapsed = current - data.lastAccessTime;
                    long remain = interval - elapsed;
                    if (remain > 0) {
                        try {
                            Thread.sleep(remain);
                        } catch (InterruptedException e) {
                        }
                    }
                    data.lastAccessTime = current;
                }
            }
        }
    }

}