Skip to content

Commit d59eeb5

Browse files
committed
started integrating google analytics.
1 parent dc4fd6e commit d59eeb5

File tree

13 files changed

+375
-2
lines changed

13 files changed

+375
-2
lines changed

.idea/jme3-spaceshift-editor.iml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build-native.xml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,11 @@
7676
<include name="*"/>
7777
</fileset>
7878
<fileset dir="build/libs/svg">
79-
<include name="*"/>
80-
</fileset>
79+
<include name="*"/>
80+
</fileset>
81+
<fileset dir="build/libs/http">
82+
<include name="*"/>
83+
</fileset>
8184
</classpath>
8285
</javac>
8386

@@ -118,11 +121,18 @@
118121
</fileset>
119122
</copy>
120123

124+
<copy todir="dist/libs/http">
125+
<fileset dir="externalLibs/http">
126+
<include name="*"/>
127+
</fileset>
128+
</copy>
129+
121130
<fx:resources id="appRes">
122131
<fx:fileset dir="dist" includes="jme3-spaceshift-editor.jar"/>
123132
<fx:fileset dir="dist" includes="libs/*"/>
124133
<fx:fileset dir="dist" includes="libs/jME/*"/>
125134
<fx:fileset dir="dist" includes="libs/svg/*"/>
135+
<fx:fileset dir="dist" includes="libs/http/*"/>
126136
<fx:fileset dir="package"/>
127137
</fx:resources>
128138

libs/http/commons-codec-1.9.jar

258 KB
Binary file not shown.

libs/http/commons-logging-1.2.jar

60.4 KB
Binary file not shown.

libs/http/httpclient-4.5.2.jar

719 KB
Binary file not shown.

libs/http/httpcore-4.4.4.jar

319 KB
Binary file not shown.

src/com/ss/editor/Editor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.jme3.system.NativeLibraryLoader;
2626
import com.jme3x.jfx.injfx.JmeToJFXApplication;
2727
import com.jme3x.jfx.util.os.OperatingSystem;
28+
import com.ss.editor.analytics.google.GAnalytics;
2829
import com.ss.editor.config.Config;
2930
import com.ss.editor.config.EditorConfig;
3031
import com.ss.editor.executor.impl.EditorThreadExecutor;
@@ -364,11 +365,15 @@ public void update() {
364365

365366
} catch (final AssetNotFoundException | ArrayIndexOutOfBoundsException | NullPointerException | StackOverflowError e) {
366367
LOGGER.warning(e);
368+
GAnalytics.sendException(e, true);
369+
GAnalytics.waitForSend();
367370
final WorkspaceManager workspaceManager = WorkspaceManager.getInstance();
368371
workspaceManager.save();
369372
System.exit(1);
370373
} catch (final RendererException | IllegalStateException e) {
371374
LOGGER.warning(e);
375+
GAnalytics.sendException(e, true);
376+
GAnalytics.waitForSend();
372377
final WorkspaceManager workspaceManager = WorkspaceManager.getInstance();
373378
workspaceManager.clear();
374379
workspaceManager.save();

src/com/ss/editor/JFXApplication.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import static java.nio.file.Files.newOutputStream;
55

66
import com.jme3x.jfx.injfx.JmeToJFXApplication;
7+
import com.ss.editor.analytics.google.GAEvent;
8+
import com.ss.editor.analytics.google.GAnalytics;
79
import com.ss.editor.config.CommandLineConfig;
810
import com.ss.editor.config.Config;
911
import com.ss.editor.config.EditorConfig;
@@ -151,6 +153,9 @@ public void start(final Stage stage) throws Exception {
151153

152154
public void onExit() {
153155

156+
GAnalytics.sendEvent(GAEvent.Category.EDITOR,
157+
GAEvent.Action.EDITOR_CLOSED, GAEvent.Label.THE_EDITOR_WAS_CLOSED);
158+
154159
final EditorConfig config = EditorConfig.getInstance();
155160
config.save();
156161

@@ -159,6 +164,8 @@ public void onExit() {
159164
final Editor editor = Editor.getInstance();
160165
editor.destroy();
161166
});
167+
168+
GAnalytics.waitForSend();
162169
}
163170

164171
/**
@@ -167,10 +174,15 @@ public void onExit() {
167174
public void buildScene() {
168175
this.scene = EditorFXSceneBuilder.build(stage);
169176
this.scene.notifyFinishBuild();
177+
170178
final Editor editor = Editor.getInstance();
171179
final EditorThreadExecutor executor = EditorThreadExecutor.getInstance();
172180
executor.addToExecute(() -> bind(editor, scene.getImageView(), editor.getViewPort()));
181+
173182
JMEFilePreviewManager.getInstance();
183+
184+
GAnalytics.sendEvent(GAEvent.Category.EDITOR,
185+
GAEvent.Action.EDITOR_LAUNCHED, GAEvent.Label.THE_EDITOR_WAS_LAUNCHED);
174186
}
175187

176188
/**
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.ss.editor.analytics.google;
2+
3+
/**
4+
* @author JavaSaBr
5+
*/
6+
public interface GAEvent {
7+
8+
interface Category {
9+
String EDITOR = "Editor";
10+
}
11+
12+
interface Action {
13+
String EDITOR_LAUNCHED = "Launched";
14+
String EDITOR_CLOSED = "Closed";
15+
String OPEN = "Open";
16+
String CLOSE = "Close";
17+
}
18+
19+
interface Label {
20+
String THE_EDITOR_WAS_CLOSED = "The editor was closed";
21+
String THE_EDITOR_WAS_LAUNCHED = "The editor was launched";
22+
String EXPORT_DESTINATION_CHOOSER = "Export destination chooser";
23+
}
24+
}
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
package com.ss.editor.analytics.google;
2+
3+
import static org.apache.http.impl.client.HttpClients.createMinimal;
4+
import static rlib.util.StringUtils.isEmpty;
5+
6+
import com.ss.editor.EditorThread;
7+
8+
import org.apache.http.StatusLine;
9+
import org.apache.http.client.methods.CloseableHttpResponse;
10+
import org.apache.http.client.methods.HttpPost;
11+
import org.apache.http.entity.ByteArrayEntity;
12+
import org.apache.http.impl.client.CloseableHttpClient;
13+
import org.jetbrains.annotations.NotNull;
14+
import org.jetbrains.annotations.Nullable;
15+
16+
import java.io.IOException;
17+
import java.io.PrintWriter;
18+
import java.io.StringWriter;
19+
import java.io.UnsupportedEncodingException;
20+
import java.net.URLEncoder;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
import java.util.concurrent.atomic.AtomicInteger;
24+
25+
import rlib.concurrent.util.ConcurrentUtils;
26+
import rlib.logging.Logger;
27+
import rlib.logging.LoggerManager;
28+
import rlib.util.StringUtils;
29+
import rlib.util.linkedlist.LinkedList;
30+
import rlib.util.linkedlist.LinkedListFactory;
31+
32+
/**
33+
* @author JavaSaBr
34+
*/
35+
public class GAnalytics extends EditorThread {
36+
37+
private static final Logger LOGGER = LoggerManager.getLogger(GAnalytics.class);
38+
39+
public static final String PARAM_PROTOCOL_VERSION = "v";
40+
public static final String PARAM_TRACKING_ID = "tid";
41+
public static final String PARAM_CLIENT_ID = "cid";
42+
public static final String PARAM_HIT_TYPE = "t";
43+
public static final String PARAM_DATA_SOURCE = "ds";
44+
public static final String PARAM_QUEUE_TIME = "qt";
45+
public static final String PARAM_CACHE_BUSTER = "z";
46+
public static final String PARAM_USER_ID = "uid";
47+
public static final String PARAM_SESSION_CONTROL = "sc";
48+
public static final String PARAM_SCREEN_RESOLUTION = "sr";
49+
public static final String PARAM_USER_LANGUAGE = "ul";
50+
public static final String PARAM_APPLICATION_VERSION = "av";
51+
public static final String PARAM_EVENT_CATEGORY = "ec";
52+
public static final String PARAM_EVENT_ACTION = "ea";
53+
public static final String PARAM_EVENT_LABEL = "el";
54+
public static final String PARAM_EVENT_VALUE = "ev";
55+
public static final String PARAM_USER_TIMING_CATEGORY = "utc";
56+
public static final String PARAM_USER_TIMING_VAR_NAME = "utv";
57+
public static final String PARAM_USER_TIMING_TIME = "utt";
58+
public static final String PARAM_USER_TIMING_LABEL = "utl";
59+
public static final String PARAM_EXCEPTION_DESCRIPTION = "exd";
60+
public static final String PARAM_IS_EXCEPTION_FATAL = "exf";
61+
public static final String PARAM_CUSTOM_DIMENSION = "cd";
62+
63+
public static final String FIELD_OS = PARAM_CUSTOM_DIMENSION + "1";
64+
public static final String FIELD_GRAPHICS_ADAPTER = PARAM_CUSTOM_DIMENSION + "2";
65+
66+
public static final String PROP_ANALYTICS_HOST = "http://www.google-analytics.com/collect";
67+
public static final String PROP_TRACKING_ID = "UA-89459340-1";
68+
public static final String PROP_CLIENT_ID = "89459340";
69+
70+
private static final GAnalytics INSTANCE = new GAnalytics();
71+
72+
public static GAnalytics getInstance() {
73+
return INSTANCE;
74+
}
75+
76+
public static void waitForSend() {
77+
final GAnalytics instance = getInstance();
78+
final AtomicInteger progressCount = instance.progressCount;
79+
if(progressCount.get() < 1) return;
80+
ConcurrentUtils.wait(progressCount, 2000);
81+
}
82+
83+
public static void sendEvent(@NotNull final String category, @NotNull final String action) {
84+
sendEvent(category, action, null, null);
85+
}
86+
87+
public static void sendEvent(@NotNull final String category, @NotNull final String action, @Nullable final String label) {
88+
sendEvent(category, action, label, null);
89+
}
90+
91+
public static void sendEvent(@NotNull final String category, @NotNull final String action, @Nullable final String label, @Nullable final String value) {
92+
93+
final Map<String, Object> parameters = new HashMap<>();
94+
parameters.put(PARAM_EVENT_CATEGORY, category);
95+
parameters.put(PARAM_EVENT_ACTION, action);
96+
97+
if(!isEmpty(label)) parameters.put(PARAM_EVENT_LABEL, label);
98+
if(!isEmpty(value)) parameters.put(PARAM_EVENT_VALUE, value);
99+
100+
send(HitType.EVENT, parameters);
101+
}
102+
103+
/**
104+
* Send an exception.
105+
*
106+
* @param exception the exception.
107+
* @param fatal true if the exception is fatal.
108+
*/
109+
public static void sendException(@NotNull final Throwable exception, final boolean fatal) {
110+
111+
final StringWriter writer = new StringWriter();
112+
final PrintWriter printWriter = new PrintWriter(writer);
113+
114+
exception.printStackTrace(printWriter);
115+
116+
final String localizedMessage = exception.getLocalizedMessage();
117+
final String stackTrace = writer.toString();
118+
119+
final Map<String, Object> parameters = new HashMap<>();
120+
parameters.put(PARAM_EXCEPTION_DESCRIPTION, localizedMessage + ":\n" + stackTrace);
121+
parameters.put(PARAM_IS_EXCEPTION_FATAL, fatal);
122+
123+
send(HitType.EXCEPTION, parameters);
124+
}
125+
126+
private static void send(final HitType hitType, final Map<String, Object> parameters) {
127+
parameters.put(PARAM_HIT_TYPE, hitType.toString());
128+
send(parameters);
129+
}
130+
131+
private static void send(final Map<String, Object> parameters) {
132+
getInstance().addTask(() -> doSend(parameters));
133+
}
134+
135+
private static void doSend(final Map<String, Object> parameters) {
136+
137+
String os = null;
138+
String graphicsAdapter = null;
139+
140+
final GAnalytics instance = getInstance();
141+
final AtomicInteger progressCount = instance.progressCount;
142+
143+
System.out.println("start sending " + parameters);
144+
145+
try(final CloseableHttpClient httpClient = createMinimal()) {
146+
147+
parameters.put(PARAM_PROTOCOL_VERSION, "1");
148+
parameters.put(PARAM_TRACKING_ID, PROP_TRACKING_ID);
149+
parameters.put(PARAM_CLIENT_ID, PROP_CLIENT_ID);
150+
151+
if(!StringUtils.isEmpty(os)) parameters.put(FIELD_OS, os);
152+
if(!StringUtils.isEmpty(graphicsAdapter)) parameters.put(FIELD_GRAPHICS_ADAPTER, graphicsAdapter);
153+
154+
final String stringParameters = buildParameters(parameters);
155+
final byte[] byteParameters = stringParameters.getBytes("UTF-8");
156+
157+
final HttpPost post = new HttpPost(PROP_ANALYTICS_HOST);
158+
post.setEntity(new ByteArrayEntity(byteParameters));
159+
160+
final CloseableHttpResponse response = httpClient.execute(post);
161+
final StatusLine statusLine = response.getStatusLine();
162+
163+
if (statusLine.getStatusCode() != 200) {
164+
LOGGER.warning("failed analytics request: " + response);
165+
}
166+
167+
System.out.println("finished sending.");
168+
169+
} catch (final IOException e) {
170+
LOGGER.warning(e);
171+
} finally {
172+
progressCount.decrementAndGet();
173+
ConcurrentUtils.notifyAll(progressCount);
174+
}
175+
}
176+
177+
private static String buildParameters(final Map<String, Object> parameters) {
178+
179+
final StringBuilder builder = new StringBuilder();
180+
181+
parameters.forEach((key, value) -> appendParam(builder, key, value));
182+
183+
return builder.toString();
184+
}
185+
186+
private static void appendParam(final StringBuilder builder, final String key, final Object value) {
187+
if(value == null) return;
188+
else if(builder.length() > 1) {
189+
builder.append('&');
190+
}
191+
192+
builder.append(key).append('=');
193+
194+
if(value instanceof String) {
195+
try {
196+
builder.append(URLEncoder.encode((String) value, "UTF-8"));
197+
} catch (final UnsupportedEncodingException e) {
198+
builder.append((String) value);
199+
}
200+
}
201+
}
202+
203+
/**
204+
* The queue with tasks.
205+
*/
206+
@NotNull
207+
private final LinkedList<Runnable> queue;
208+
209+
/**
210+
* The count of sending.
211+
*/
212+
private final AtomicInteger progressCount;
213+
214+
public GAnalytics() {
215+
setName("GAnalytics Thread");
216+
this.queue = LinkedListFactory.newLinkedList(Runnable.class);
217+
this.progressCount = new AtomicInteger();
218+
start();
219+
}
220+
221+
/**
222+
* Add a new task for executing.
223+
*
224+
* @param runnable a new task.
225+
*/
226+
private void addTask(@NotNull final Runnable runnable) {
227+
progressCount.incrementAndGet();
228+
synchronized (queue) {
229+
queue.add(runnable);
230+
ConcurrentUtils.notifyAllInSynchronize(queue);
231+
}
232+
}
233+
234+
@Override
235+
public void run() {
236+
for(;;) {
237+
238+
Runnable next = null;
239+
240+
synchronized (queue) {
241+
next = queue.pollFirst();
242+
if(next == null) {
243+
ConcurrentUtils.waitInSynchronize(queue);
244+
continue;
245+
}
246+
}
247+
248+
try {
249+
next.run();
250+
} catch (final Exception e) {
251+
LOGGER.warning(e.getMessage(), e);
252+
}
253+
}
254+
}
255+
}

0 commit comments

Comments
 (0)