com.arcbees.analytics.client.ClientAnalytics.java Source code

Java tutorial

Introduction

Here is the source code for com.arcbees.analytics.client.ClientAnalytics.java

Source

/**
 * Copyright 2014 ArcBees Inc.
 *
 * 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 com.arcbees.analytics.client;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import com.arcbees.analytics.shared.AnalyticsImpl;
import com.arcbees.analytics.shared.AnalyticsPlugin;
import com.arcbees.analytics.shared.GaAccount;
import com.arcbees.analytics.shared.HitType;
import com.arcbees.analytics.shared.ProtocolTranslator;
import com.arcbees.analytics.shared.options.AnalyticsOptions;
import com.arcbees.analytics.shared.options.CreateOptions;
import com.arcbees.analytics.shared.options.GeneralOptions;
import com.arcbees.analytics.shared.options.TimingOptions;
import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArrayMixed;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.Timer;
import com.google.inject.Inject;

public class ClientAnalytics extends AnalyticsImpl {
    private static final Logger LOGGER = Logger.getLogger(ClientAnalytics.class.getName());
    private final Map<String, Double> timingEvents = new HashMap<>();
    private final String fallbackPath;

    private final Timer fallbackInitTimer = new Timer() {
        @Override
        public void run() {
            if (loadFallback()) {
                LOGGER.info("Universal analytics not loaded after 10 seconds, using fallback");
            }
        }
    };

    @Inject
    ClientAnalytics(@GaAccount String userAccount, @AutoCreate boolean autoCreate, @AutoInject boolean autoInject,
            @TrackInitialPageView boolean trackInitialPageView, @FallbackPath String fallbackPath) {
        super(userAccount);

        this.fallbackPath = fallbackPath;

        if (autoInject) {
            init();
        }

        if (autoCreate) {
            create().go();
            if (trackInitialPageView) {
                sendPageView().go();
            }
        }
    }

    private void call(JSONValue... params) {
        final JSONArray aryParams = new JSONArray();
        for (JSONValue p : params) {
            aryParams.set(aryParams.size(), p);
        }
        nativeCall(aryParams.getJavaScriptObject());
    }

    @Override
    public CreateOptions create(final String userAccount) {
        return new AnalyticsOptions(new JsonOptionsCallback() {

            @Override
            public void onCallback(JSONObject options) {
                call(new JSONString("create"), new JSONString(userAccount), options);
                setGlobalSettings().forceSsl(true).go();
            }
        }).createOptions();
    }

    @Override
    public void enablePlugin(AnalyticsPlugin plugin) {
        if (plugin.getJsName() != null) {
            call(new JSONString("require"), new JSONString(plugin.getFieldName()),
                    new JSONString(plugin.getJsName()));
        } else {
            call(new JSONString("require"), new JSONString(plugin.getFieldName()));
        }
    }

    @Override
    public TimingOptions endTimingEvent(String trackerName, String timingCategory, String timingVariableName) {
        final String key = getTimingKey(timingCategory, timingVariableName);
        if (timingEvents.containsKey(key)) {
            return sendTiming(trackerName, timingCategory, timingVariableName,
                    (int) (Duration.currentTimeMillis() - timingEvents.remove(key)));
        }
        return new AnalyticsOptions(new JsonOptionsCallback() {

            @Override
            public void onCallback(JSONObject options) {
                // Do nothing a timing event was ended before it was started.
                // This is here just to stop a crash.
            }
        }).timingOptions(timingCategory, timingVariableName, 0);
    }

    private void init() {
        nativeInit();
        if (!fallbackPath.isEmpty()) {
            fallbackInitTimer.schedule(10000);
        }
    }

    public void fallback(JsArrayMixed arguments) {
        if ("send".equals(arguments.getString(0))) {
            JSONObject jsonOptions = new JSONObject(arguments.getObject(arguments.length() - 1));
            StringBuilder url = new StringBuilder();
            url.append(fallbackPath).append("?");
            url.append(ProtocolTranslator.getFieldName("hitType")).append("=")
                    .append(URL.encodeQueryString(arguments.getString(1)));

            for (String key : jsonOptions.keySet()) {
                if (!"hitCallback".equals(key)) {
                    JSONValue jsonValue = jsonOptions.get(key);
                    String strValue = "";
                    if (jsonValue.isBoolean() != null) {
                        strValue = jsonValue.isBoolean().booleanValue() + "";
                    } else if (jsonValue.isNumber() != null) {
                        strValue = jsonValue.isNumber().doubleValue() + "";
                    } else if (jsonValue.isString() != null) {
                        strValue = jsonValue.isString().stringValue();
                    }
                    url.append("&").append(ProtocolTranslator.getFieldName(key)).append("=")
                            .append(URL.encodeQueryString(strValue));
                }
            }
            try {
                RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url.toString());
                requestBuilder.setCallback(new RequestCallback() {

                    @Override
                    public void onResponseReceived(Request request, Response response) {
                        // TODO call hitcallback if needed.
                    }

                    @Override
                    public void onError(Request request, Throwable exception) {
                        // TODO Auto-generated method stub
                    }
                });
                requestBuilder.send();
            } catch (RequestException e) {
            }
        }
    }

    private native boolean loadFallback() /*-{
                                          var name = $wnd['GoogleAnalyticsObject'];
                                          var preCalled = $wnd[name].q;
                                          if (preCalled !== undefined) {
                                          var that = this;
                                          $wnd[name] = function() {
                                          // CHECKSTYLE_OFF
                                          $entry(that.@com.arcbees.analytics.client.ClientAnalytics::fallback(Lcom/google/gwt/core/client/JsArrayMixed;)(arguments));
                                          // CHECKSTYLE_ON
                                          };
                                          for (var i = 0; i < preCalled.length; i++) {
                                          $wnd[name].apply(null, preCalled[i]);
                                          }
                                          return true;
                                          }
                                          return false;
                                          }-*/;

    private native void nativeInit() /*-{
                                     (function(i, s, o, g, r, a, m) {
                                     i['GoogleAnalyticsObject'] = r;
                                     i[r] = i[r] || function() {
                                     (i[r].q = i[r].q || []).push(arguments)
                                     }, i[r].l = 1 * new Date();
                                     a = s.createElement(o), m = s.getElementsByTagName(o)[0];
                                     a.async = 1;
                                     a.src = g;
                                     m.parentNode.insertBefore(a, m)
                                     })($wnd, $doc, 'script', '//www.google-analytics.com/analytics.js',
                                     '__ua');
                                     }-*/;

    private native void nativeCall(JavaScriptObject params) /*-{
                                                            $wnd.__ua.apply(null, params);
                                                            }-*/;

    @Override
    public AnalyticsOptions send(final String trackerName, final HitType hitType) {
        return new AnalyticsOptions(new JsonOptionsCallback() {

            @Override
            public void onCallback(JSONObject options) {
                call(new JSONString(trackerName == null ? "send" : trackerName + ".send"),
                        new JSONString(hitType.getFieldName()), options);
            }
        });
    }

    @Override
    public GeneralOptions setGlobalSettings() {
        return new AnalyticsOptions(new JsonOptionsCallback() {

            @Override
            public void onCallback(JSONObject options) {
                call(new JSONString("set"), options);
            }

        }).generalOptions();
    }

    @Override
    public void startTimingEvent(String timingCategory, String timingVariableName) {
        timingEvents.put(getTimingKey(timingCategory, timingVariableName), Duration.currentTimeMillis());
    }
}