Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Introduce abstract components #12468

Merged
merged 1 commit into from
Aug 24, 2018
Merged

Introduce abstract components #12468

merged 1 commit into from
Aug 24, 2018

Conversation

tobrun
Copy link
Member

@tobrun tobrun commented Jul 24, 2018

Follow up from #12449 and #12391.

This PR makes the following components configurable:

  • logger
  • http client
  • telemetry

@tobrun tobrun added the Android Mapbox Maps SDK for Android label Jul 24, 2018
@tobrun tobrun added this to the android-v6.4.0 milestone Jul 24, 2018
@tobrun tobrun self-assigned this Jul 24, 2018
@tobrun tobrun force-pushed the tvn-modules branch 2 times, most recently from d57b421 to d9a24e1 Compare July 24, 2018 14:14
@tobrun
Copy link
Member Author

tobrun commented Jul 25, 2018

To satisfy semver, I need to refactor telemetry module into an abstract class and add static methods

Copy link
Member

@LukasPaczos LukasPaczos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work so far!

apply plugin: 'com.android.library'

android {
compileSdkVersion 28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use dependencies.gradle references here?

if (context == null) {
throw new IllegalStateException("MapboxConfigurationWrapper isn't initialised correctly.");
}
return instance.getBaseContext();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: this can return the context variable.

}

public static String getAccessToken() {
if (accessToken == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check and the exception that is thrown removes the possibility of passing a null access token.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are two places in code where this is referenced:

  • Telemetry.java -> no issue there
  • Mapbox.java -> indeed an issue
    added try/catch and return null in those cases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to fixup Mapbox.java for unit tests, will look for a solution without the try catch

@@ -97,7 +98,7 @@ private void showTelemetryDialog() {
builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Telemetry.enableOnUserRequest();
Mapbox.getTelemetry().enableOnUserRequest();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will throw an NPE if the access token is null.

@@ -111,7 +112,7 @@ public void onClick(DialogInterface dialog, int which) {
builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Telemetry.disableOnUserRequest();
Mapbox.getTelemetry().disableOnUserRequest();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will throw an NPE if the access token is null.

@@ -4,7 +4,7 @@

private static final String OPENSTREETMAP = "OpenStreetMap";
private static final String OPENSTREETMAP_ABBR = "OSM";
static final String TELEMETRY = "Telemetry Settings";
static final String TELEMETRY = "TelemetryBase Settings";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an unnecessary result of the class name change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor issue, nice catch

@@ -17,7 +17,7 @@
* Creates a Mapbox configuration exception thrown by MapboxMap when the SDK hasn't been properly initialised.
*/
public MapboxConfigurationException() {
super("\nUsing MapView requires calling Mapbox.getInstance(Context context, String accessToken) before "
super("\nUsing MapView requires calling Mapbox.initialize(Context context, String accessToken) before "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should still point to Mapbox.getInstance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactor issue, nice catch

@@ -4,7 +4,7 @@
import android.os.StrictMode;
import android.text.TextUtils;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.Telemetry;
import com.mapbox.mapboxsdk.telemetry.Telemetry;
Copy link
Member

@LukasPaczos LukasPaczos Jul 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in #12468 (comment), this and all other Telemetry.java changes are semver major.

@LukasPaczos
Copy link
Member

When it comes to logging, I feel like tagging all our logs with a unified tag, like Mapbox, would be easier to browse and search for us and users. Also, we need to add a custom, Timber logger definition to the test app to leverage Timber.


static void log(int type, String errorMessage) {
if (logEnabled) {
Timber.log(type, errorMessage);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rely on the Logger here instead of Timber? A user might want to use our http module with a different LoggerDefinition.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, timber also removed from build.gradle

@tobrun tobrun force-pushed the tvn-modules branch 2 times, most recently from 5e8cec2 to 9606d09 Compare July 25, 2018 11:14
@zugaldia
Copy link
Member

When it comes to logging, I feel like tagging all our logs with a unified tag, like Mapbox, would be easier to browse and search for us and users.

A compromise between granularity and consistency could be to have all tags start with the same Mapbox-specific prefix (say Mbx).

@tobrun
Copy link
Member Author

tobrun commented Jul 25, 2018

When it comes to logging, I feel like tagging all our logs with a unified tag, like Mapbox, would be easier to browse and search for us and users.

A compromise between granularity and consistency could be to have all tags start with the same Mapbox-specific prefix (say Mbx).

Yes, this is already in place with https://github.com/mapbox/mapbox-gl-native/pull/12468/files#diff-8f41632c292f442353443b7ff4520ca1R16

@zugaldia @LukasPaczos, before re-reviewing, I will be working on removing the different modules. This is not a hard requirement.

@tobrun tobrun changed the title Introduce modular components Introduce abstract components Jul 25, 2018
Copy link
Member

@zugaldia zugaldia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small request to move all new implementations into the same package. Otherwise this is looking great, lots of moving pieces well taken care of.

@@ -0,0 +1,196 @@
package com.mapbox.mapboxsdk.http;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this file to a modules folder?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible yes, but to completely exclude okhttp, the user would also have to exclude com.mapbox.mapboxsdk.http.HttpRequestUtil which we can't move due to semver. I'm suggesting postponing changing package names until next major release.

@@ -1,75 +1,157 @@
package com.mapbox.mapboxsdk.maps;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, if this is the implementation, could we move this file to a modules folder?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not possible due to semver

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - could we move everything we can (new classes) and leave the rest for 7.x?

@@ -39,14 +41,15 @@ public void onCreate() {
private boolean initializeLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
// You should not init your app in this process.male
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad copypasta?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great catch

@LukasPaczos
Copy link
Member

Looks good to me!

I'm leaving the final word to @zugaldia.

@tobrun tobrun force-pushed the tvn-modules branch 4 times, most recently from e13c993 to 4a182a7 Compare July 26, 2018 18:32
@tobrun
Copy link
Member Author

tobrun commented Jul 26, 2018

@LukasPaczos @zugaldia another iteration on this PR, would love another round of 👀

Copy link
Contributor

@jaegs jaegs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changeset is massive which makes it a bit hard to review. Perhaps it could be broken up into smaller pieces.

Also any chance using git mv of git cp will preserve some of the blame?

*/
@Deprecated
public static void setOkHttpClient(OkHttpClient client) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method will require okhttp to build

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is one of the files that would need to be excluded, due to semver we can't change this

* @param etag http header, identifier for a specific version of a resource
* @param modified http header, used to determine if a resource hasn't been modified since
*/
public abstract void executeRequest(HttpRequestResponder httpRequest, long nativePtr, String resourceUrl,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Favor composition over inheritance" is one of the rules from Effective Java

https://stackoverflow.com/questions/2399544/difference-between-inheritance-and-composition

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

composition is provided in the module file here. The HttpRequest class is the contract between the SDK and the alternate implementation. How would you enforce the availability of predefined methods, the sdk needs a predefined hook, either an interface or an abstract class?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An interface is generally preferable since it doesn't lock the API user into single inheritance. I think an interface should work here unless I'm missing something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead with an interface for HttpRequest, other functionality besides executeRequest and cancel was extracted in separate classes. Looks a lot cleaner now, thank you for the clarification.


@Override
public void v(String tag, String msg) {
Log.v(String.format(TAG_TEMPLATE, tag), msg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will perform string regex even if logging is off.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wasn't aware of this, having this TAG_TEMPLATE formatting was only a nice to have, will remove it.

httpRequest.handleFailure(type, errorMessage);
}

private void logFailure(int type, String errorMessage, String requestUrl) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this method specific to OKHttp?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move it up to the base class, though will apply composition to it so it will be found in a separate helper class.

if(severity == EventSeverity::Debug){
auto method = _class.GetStaticMethod<Signature>(env, "d");
_class.Call(env, method, tag, message);
}else if(severity == EventSeverity::Info){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else
^

@tobrun tobrun force-pushed the tvn-modules branch 2 times, most recently from 802e0bf to d0fbde0 Compare August 15, 2018 10:46
@LukasPaczos LukasPaczos removed this from the android-v6.4.0 milestone Aug 15, 2018
@tobrun tobrun force-pushed the tvn-modules branch 2 times, most recently from e2c0fd8 to b540403 Compare August 22, 2018 09:17
Copy link
Member

@LukasPaczos LukasPaczos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the concerns from #12468 (comment) but couldn't we add the Mbx- prefix to every TAG that is currently being created in all of the classes instead?

With the current setup and the TelemetryDefinition being returned in the public API, TelemetryImpl#onAppUserTurnstileEvent and TelemetryImpl#onGestureInteraction are not package-restricted and can be possibly used to pollute our telemetry data.

@@ -4,7 +4,7 @@

private static final String OPENSTREETMAP = "OpenStreetMap";
private static final String OPENSTREETMAP_ABBR = "OSM";
static final String TELEMETRY = "Telemetry Settings";
static final String TELEMETRY = "TelemetryImpl Settings";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor artifact?

* Create a new concrete implementation of HttpRequest.
*
* @return a new instance of an HttpRequest
*/

This comment was marked as resolved.

* Get the concrete implementation of TelemetryDefinition
*
* @return a single instance of Telemetry
*/

This comment was marked as resolved.

HttpRequest createHttpRequest();

@Nullable
TelemetryDefinition obtianTelemetry();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TYPO: obtainTelemetry

*/
public class ModuleProviderImpl implements ModuleProvider {

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about moving this javadoc to the interface definition?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: since the javadoc in the interface is identical, we can remove this one.

Field field = interval.getClass().getDeclaredField("interval");
field.setAccessible(true);
Integer intervalValue = (Integer) field.get(interval);
return getInstance().setSessionIdRotationInterval(intervalValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should get the TelemetryImpl reference using the Mapbox#getTelemetry and check for nullability to avoid crashing.

*/
@Deprecated
public static void enableOnUserRequest() {
getInstance().setUserTelemetryRequestState(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should get the TelemetryImpl reference using the Mapbox#getTelemetry and check for nullability to avoid crashing.

*/
@Deprecated
public static void disableOnUserRequest() {
getInstance().setUserTelemetryRequestState(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should get the TelemetryImpl reference using the Mapbox#getTelemetry and check for nullability to avoid crashing.

@@ -70,7 +73,10 @@ private void initializeMapbox() {
String accessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
validateAccessToken(accessToken);
Mapbox.getInstance(getApplicationContext(), accessToken);
Telemetry.updateDebugLoggingEnabled(true);
TelemetryDefinition telemetry = Mapbox.getTelemetry();
if (telemetry != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about removing the null-check here, or crashing the app with a clearer exception, to catch start-up telemetry regressions during internal testing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added:

    if (telemetry == null) {
      throw new IllegalStateException("Telemetry was unavailable during test application start.");
    }

}
}

public static void initialize() {
Copy link
Member

@LukasPaczos LukasPaczos Aug 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be impactful but breaks the semver. How about leaving an empty impl instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great catch!

@tobrun tobrun force-pushed the tvn-modules branch 2 times, most recently from 5fe8f97 to 123d2b4 Compare August 22, 2018 10:55
*/
public class ModuleProviderImpl implements ModuleProvider {

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: since the javadoc in the interface is identical, we can remove this one.

return new HttpRequestImpl();
}

/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: since the javadoc in the interface is identical, we can remove this one.

@tobrun tobrun force-pushed the tvn-modules branch 3 times, most recently from 4d4d8bd to 1a4697a Compare August 22, 2018 12:20
Copy link
Member

@LukasPaczos LukasPaczos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🚀

Copy link
Member

@zugaldia zugaldia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📦

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Android Mapbox Maps SDK for Android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants