Categories
discuss

Kotlin: How do I get characters after “@” in a string?

I have a string that is an email. I want to be able to get the domain part of the email no matter what the string/email is. Essentially I’m wanting to get hold of the characters after the @ part of the string. For example, for testing@kotlin.com, I’m after the kotlin.com part.

val emailString = “hello@world.com”

Answer

Note: Ivan Wooll’s answer brings up the point of using substringAfterLast, which is a very useful utility, though it is important to keep in mind that it cannot return null and instead defaults to a provided default value (this is the original string, if nothing is specified).

I personally prefer dealing with null in cases where invalid input is a reasonable concern, rather than e.g. an empty string, because it’s a much clearer indication that the delimiter was not found, and this special case can be easily handled by chaining ?:, ?., let, etc.

Here’s an example of possibly-unwanted behavior:

string           | string.substringAfterLast("@")
-------------------------------------------------
"domain.com"     | "domain.com" !
"@domain.com"    | "domain.com"
"foo@domain.com" | "domain.com"

Just for the sake of completeness:

val string = "hello@world.com"

val index = string.indexOf('@')

val domain: String? = if (index == -1) null else string.substring(index + 1)

This assigns the part after @ to domain if it exists, otherwise null.


For learning, IntelliJ’s Java -> Kotlin converter may be of use.

By default, this shortcut is usually mapped to Ctrl+Alt+Shift+K.

You could even make this an extension property:

val String.domain: String?
    get() {
        val index = string.indexOf('@')
        return if (index == -1) null else string.substring(index + 1)
    }

and then you would be able to do

println("hello@world.com".domain)

You could shorten this code to one line with let:

string.indexOf('@').let { if (it == -1) null else string.substring(it + 1) }

Here’s a similar question in Java.

Categories
discuss

Testing content of list ignoring some of the fields

I have a scenario where I receive a list from a method call and I would like to assert that the list contains the correct elements. One way to do this would be to look for some detail in each element to see which expected element to compare with – eg. a name. However the elements also contains a random generated UUID that I do not care about comparing.
And then I thought a test tool might come to my rescue. Take the following simplified example.

I have a class Dog:

public class Dog {
    private String name;
    private Integer age;
}

They are contained in a list:

List<Dog> dogs = ... many dogs

Now I want to test that the list contains the expected dogs, but for some reason I do not know some of the fields – let us say age. I have tried both using assertj and hamcrest but I cannot find the correct solution that both compares two lists while also ignoring some of the fields.

Until now this is what I have (using hamcrest):

List<Dog> actualDogs = codeUndertest.findDogs(new Owner("Basti"));
List<Dog> expectedDogs = createExpectedListOfDogsWithoutTheAge();

Matcher.assertThat(actualDogs.get(0), Matcher.is(com.shazam.shazamcrest.matcher.Matchers
    .sameBeanAs(expectedDogs.(0))
    .ignoring("age")
))

This works but it only compares two objects of class Dog. How do I compare all the dogs in the two list?
Bonus question: how do I compare the lists without knowing the order or if I only need to assert that the expected dogs are contained in the list.

Answer

Give a try to AssertJ’s usingElementComparatorIgnoringFields:

Employee bill = new Employee("Bill", 60, "Micro$oft");
Employee appleBill = new Employee("Billie", 60, "Apple");
List<Employee> employees = newArrayList(bill, appleBill);

Employees[] expectedEmployees = { new Employee("Bill", 60, "Google"), 
                                  new Employee("Billie", 60, "Facebook") };
// this assertion succeeds as we don't compare the company field.     
assertThat(employees).usingElementComparatorIgnoringFields("company")
                     .contains(expectedEmployees);

edit: The new recursive comparison API can be used, it gives much finer control about what is being compared: https://assertj.github.io/doc/#assertj-core-recursive-comparison-ignoring-fields

Categories
discuss

okhttp – Interceptor – Stopping non-fatal exceptions from being logged to Crashlytics

I’m using Retrofit in an android app, and that in turn means im using OkHttp. I’ve just gone to Alpha and seeing in my crashlytics report a number of non-fatal exceptions being logged. All of these are stemming from my okhttp interceptor, and then exceptions being logged all seem to be things that are valid in situations where maybe the network is spotty or if connection drops out etc.

How can I make it so these exceptions are not logged out to crashlytics and thus cluttering up my view of exceptions occuring in the app?


Some examples of the exceptions:

> Non-fatal Exception: javax.net.ssl.SSLHandshakeException
Connection closed by peer
okhttp3.internal.connection.RealConnection.connectTls (RealConnection.java:281)
okhttp3.internal.connection.RealConnection.establishProtocol (RealConnection.java:251)
okhttp3.internal.connection.RealConnection.connect (RealConnection.java:151)
okhttp3.internal.connection.StreamAllocation.findConnection (StreamAllocation.java:192)
okhttp3.internal.connection.StreamAllocation.findHealthyConnection (StreamAllocation.java:121)
okhttp3.internal.connection.StreamAllocation.newStream (StreamAllocation.java:100)
okhttp3.internal.connection.ConnectInterceptor.intercept (ConnectInterceptor.java:42)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:67)
okhttp3.internal.cache.CacheInterceptor.intercept (CacheInterceptor.java:93)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:67)
okhttp3.internal.http.BridgeInterceptor.intercept (BridgeInterceptor.java:93)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept (RetryAndFollowUpInterceptor.java:120)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:67)
MY_INTERCEPTOR.intercept (AuthenticationInterceptor.java:30)

and

> Non-fatal Exception: javax.net.ssl.SSLException
Read error: ssl=0xdee45cc0: I/O error during system call, Software caused connection abort
okio.Okio$2.read (Okio.java:139)
okio.AsyncTimeout$2.read (AsyncTimeout.java:237)
okio.RealBufferedSource.indexOf (RealBufferedSource.java:345)
okio.RealBufferedSource.readUtf8LineStrict (RealBufferedSource.java:217)
okio.RealBufferedSource.readUtf8LineStrict (RealBufferedSource.java:211)
okhttp3.internal.http1.Http1Codec.readResponseHeaders (Http1Codec.java:189)
okhttp3.internal.http.CallServerInterceptor.intercept (CallServerInterceptor.java:75)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.connection.ConnectInterceptor.intercept (ConnectInterceptor.java:45)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:67)
okhttp3.internal.cache.CacheInterceptor.intercept (CacheInterceptor.java:93)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:67)
okhttp3.internal.http.BridgeInterceptor.intercept (BridgeInterceptor.java:93)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept (RetryAndFollowUpInterceptor.java:120)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:92)
okhttp3.internal.http.RealInterceptorChain.proceed (RealInterceptorChain.java:67)
MY_INTERCEPTOR.intercept (AuthenticationInterceptor.java:30)

This is my interceptors code:

@Override
public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    Response response = chain.proceed(request);

    if( response.code() == HTTP_AUTHENTICATION_ERROR_CODE ){
        Intent intent = new Intent(ACTION_LOGOUT_ACTION);
        mContext.sendBroadcast(intent);
    }
    return response;
}

I get that I could catch any IOException from the “proceed” call, but wouldnt that mess up OkHttp’s proper handling of network errors etc?

Answer

Non-fatal Exception is logged when you call Crashlytics.logException(Exception)explicitly in code

Please Read below information :

Crashlytics for Android lets you log caught exceptions in your app’s catch blocks! To use this feature, simply add a call to Crashlytics.logException(Exception) to your catch block:

try {
  myMethodThatThrows();
} catch (Exception e) {
  Crashlytics.logException(e);
  // handle your exception here! 
}

All logged exceptions will appear as “non-fatal” issues in the Crashlytics dashboard. Your issue summary will contain all the state information you are use to getting from crashes along with breakdowns by Android version and hardware device.

Categories
discuss

Programatic username/password access with KeyCloak using external IDP brokering

I’m using Identity Brokering feature and external IDP. So, user logs in into external IDP UI, then KeyCloak broker client receives JWT token from external IDP and KeyCloak provides JWT with which we access the resources. I’ve set up Default Identitiy Provider feature, so external IDP login screen is displayed to the user on login. That means that users and their passwords are stored on external IDP.

The problem occurs when I need to log in using “Direct Access Grant” (Resource Owner Password grant) programatically in tests. As password is not stored on KeyCloak, I always get 401 Unauthorized error from KeyCloak on login. When I tried to change user password it started to work, so the problem is that user password is not provisioned on KeyCloak and using “Direct Access Grant” KeyCloak doesn’t invoke external IDP on programatic login.

I use the following code to obtain access token, but get 401 error everytime I pass valid username/password.

org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 401 / Unauthorized

Direct access grant is enabled for that client.

public static String login(final Configuration configuration) {
    final AuthzClient authzClient = AuthzClient.create(configuration);
    final AccessTokenResponse accessTokenResponse = authzClient.obtainAccessToken(USERNAME, PASSWORD);
    return accessTokenResponse.getToken();
  }

Is there any way it can be fixed? For example to call identity broker on “Direct Access Grant”, so that KeyCloak provides us it’s valid token?

Answer

The problem was that KeyCloak has no information about passwords from initial identity provider. They have a token exchange feature which should be used for programmatic token exchange.

External Token to Interanal Token Exchange should be used to achieve it.

Here is an example code in Python which does it (just place correct values in placeholders):

def login():
    idp_access_token = idp_login()
    return keycloak_token_exchange(idp_access_token)

def idp_login():
    login_data = {
        "client_id": <IDP-CLIENT-ID>,
        "client_secret": <IDP-CLIENT-SECRET>,
        "grant_type": <IDP-PASSWORD-GRANT-TYPE>,
        "username": <USERNAME>,
        "password": <PASSWORD>,
        "scope": "openid",
        "realm": "Username-Password-Authentication"
    }
    login_headers = {
        "Content-Type": "application/json"
    }
    token_response = requests.post(<IDP-URL>, headers=login_headers, data=json.dumps(login_data))
    return parse_response(token_response)['access_token']

def keycloak_token_exchange(idp_access_token):
    token_exchange_url = <KEYCLOAK-SERVER-URL> + '/realms/master/protocol/openid-connect/token'
    data = {
        'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
        'subject_token': idp_access_token,
        'subject_issuer': <IDP-PROVIDER-ALIAS>,
        'subject_token_type': 'urn:ietf:params:oauth:token-type:access_token',
        'audience': <KEYCLOAK-CLIENT-ID>
    }
    response = requests.post(token_exchange_url, data=data,
                             auth=(<KEYCLOAK-CLIENT-ID>, <KEYCLOAK-CLIENT-SECRET>))
    logger.info(response)
    return parse_response(response)['access_token']
Categories
discuss

scroll visible part of overflown div inside smaller div without jquery

I´m currently trying to move a wider div B horizontally inside an smaller <div> A using two buttons.
I found a similar problem using jquery, but doesn´t want to use the library just for this section in the code.

Here is the fiddle

I want to scroll the visible field of view using a ‘left’ and ‘right’ button to move the field 100px in either direction without using jquery but with pure Javascript, HTML and CSS.

<div id="outer-div" style="width:250px;overflow:hidden;">
  <div style="width:750px;">
    <div style="background-color:orange;width:250px;height:100px;float:left;">
    </div>
    <div style="background-color:red;width:250px;height:100px;float:left;">
    </div>
    <div style="background-color:blue;width:250px;height:100px;float:left;">
    </div>
  </div>
</div>
<button>left</button>
<button>right</button>

Answer

var outerDiv = document.getElementById('outer-div');

function moveLeft() {
  outerDiv.scrollLeft -= 100;
}

function moveRight() {
  outerDiv.scrollLeft += 100;
}

var leftButton = document.getElementById('left-button');
var rightButton = document.getElementById('right-button');

leftButton.addEventListener('click', moveLeft, false);
rightButton.addEventListener('click', moveRight, false);
<div id="outer-div" style="width:250px;overflow:hidden;">
  <div style="width:750px;">
    <div style="background-color:orange;width:250px;height:100px;float:left;">
    </div>
    <div style="background-color:red;width:250px;height:100px;float:left;">
    </div>
    <div style="background-color:blue;width:250px;height:100px;float:left;">
    </div>
  </div>
</div>
<button id="left-button">left</button>
<button id="right-button">right</button>
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..