<commit_before>/*
 * Copyright (c) 2017 deltaDNA Ltd. All rights reserved.
 * 
 * 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.deltadna.android.sdk.ads.core;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.support.annotation.Nullable;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

final class ExceptionHandler implements Thread.UncaughtExceptionHandler {
    
    @Nullable
    private final Thread.UncaughtExceptionHandler delegate =
            Thread.getDefaultUncaughtExceptionHandler();
    
    private final DbHelper db;
    
    private final String version;
    private final int versionCode;
    
    private final String versionSdk;
    private final String versionSmartAdsSdk;
    
    ExceptionHandler(
            Context context,
            String version,
            int versionCode,
            String versionSdk,
            String versionSmartAdsSdk) {
        
        db = new DbHelper(context);
        
        this.version = version;
        this.versionCode = versionCode;
        
        this.versionSdk = versionSdk;
        this.versionSmartAdsSdk = versionSmartAdsSdk;
    }
    
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        final StackTraceElement[] elements = e.getStackTrace();
        for (StackTraceElement element : elements) {
            for (AdProvider provider : AdProvider.values()) {
                if (    element.getClassName().equals(provider.cls) ||
                        element.getClassName().startsWith(provider.namespace)) {
                    
                    final StringBuilder builder = new StringBuilder()
                            .append(e)
                            .append('\n');
                    add(builder, elements);
                    if (e.getCause() != null) {
                        final Throwable cause = e.getCause();
                        builder .append("Caused by: ")
                                .append(cause)
                                .append('\n');
                        add(builder, cause.getStackTrace());
                    }
                    
                    db.add( new Date().getTime(),
                            provider.name(),
                            version,
                            versionCode,
                            versionSdk,
                            versionSmartAdsSdk,
                            provider.version(),
                            builder.toString());
                }
            }
        }
        
        if (delegate != null) delegate.uncaughtException(t, e);
    }
    
    List<String> listCrashes(AdProvider provider) {
        final Cursor cursor = db.list(
                provider.name(),
                version,
                versionCode,
                versionSdk,
                versionSmartAdsSdk,
                provider.version());
        final List<String> crashes = new ArrayList<>(cursor.getCount());
        
        while (cursor.moveToNext()) {
            crashes.add(cursor.getString(cursor.getColumnIndex(
                    DbHelper.CRASHES_STACK_TRACE)));
        }
        cursor.close();
        
        return crashes;
    }
    
    /**
     * Adds the stack trace elements to the builder, skipping elements which
     * come from the same domain, but keeping entry and exit points between
     * different domains.
     */
    private static void add(StringBuilder to, StackTraceElement[] elements) {
        StackTraceElement lastAdded = null;
        for (int i = 0; i < elements.length; i++) {
            if (i != 0 || i != elements.length - 1) {
                if (sameDomain(elements[i], elements[i-1])) {
                    continue;
                } else if (
                        lastAdded == null
                                || !lastAdded.getClassName().equals(
                                elements[i - 1].getClassName())) {
                    to      .append(elements[i-1].getClassName())
                            .append('.')
                            .append(elements[i-1].getMethodName())
                            .append('\n');
                }
            }
            
            if (i == 0) {<commit_msg>fix for e6a61a88bc6ddeaf110e034ab5832d1b9b510701 [sa-90]<commit_after>/*
 * Copyright (c) 2017 deltaDNA Ltd. All rights reserved.
 * 
 * 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.deltadna.android.sdk.ads.core;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.support.annotation.Nullable;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

final class ExceptionHandler implements Thread.UncaughtExceptionHandler {
    
    @Nullable
    private final Thread.UncaughtExceptionHandler delegate =
            Thread.getDefaultUncaughtExceptionHandler();
    
    private final DbHelper db;
    
    private final String version;
    private final int versionCode;
    
    private final String versionSdk;
    private final String versionSmartAdsSdk;
    
    ExceptionHandler(
            Context context,
            String version,
            int versionCode,
            String versionSdk,
            String versionSmartAdsSdk) {
        
        db = new DbHelper(context);
        
        this.version = version;
        this.versionCode = versionCode;
        
        this.versionSdk = versionSdk;
        this.versionSmartAdsSdk = versionSmartAdsSdk;
    }
    
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        final StackTraceElement[] elements = e.getStackTrace();
        for (StackTraceElement element : elements) {
            for (AdProvider provider : AdProvider.values()) {
                if (    element.getClassName().equals(provider.cls) ||
                        element.getClassName().startsWith(provider.namespace)) {
                    
                    final StringBuilder builder = new StringBuilder()
                            .append(e)
                            .append('\n');
                    add(builder, elements);
                    if (e.getCause() != null) {
                        final Throwable cause = e.getCause();
                        builder .append("Caused by: ")
                                .append(cause)
                                .append('\n');
                        add(builder, cause.getStackTrace());
                    }
                    
                    db.add( new Date().getTime(),
                            provider.name(),
                            version,
                            versionCode,
                            versionSdk,
                            versionSmartAdsSdk,
                            provider.version(),
                            builder.toString());
                }
            }
        }
        
        if (delegate != null) delegate.uncaughtException(t, e);
    }
    
    List<String> listCrashes(AdProvider provider) {
        final Cursor cursor = db.list(
                provider.name(),
                version,
                versionCode,
                versionSdk,
                versionSmartAdsSdk,
                provider.version());
        final List<String> crashes = new ArrayList<>(cursor.getCount());
        
        while (cursor.moveToNext()) {
            crashes.add(cursor.getString(cursor.getColumnIndex(
                    DbHelper.CRASHES_STACK_TRACE)));
        }
        cursor.close();
        
        return crashes;
    }
    
    /**
     * Adds the stack trace elements to the builder, skipping elements which
     * come from the same domain, but keeping entry and exit points between
     * different domains.
     */
    private static void add(StringBuilder to, StackTraceElement[] elements) {
        StackTraceElement lastAdded = null;
        for (int i = 0; i < elements.length; i++) {
            if (i != 0 && i != elements.length - 1) {
                if (sameDomain(elements[i], elements[i-1])) {
                    continue;
                } else if (
                        lastAdded == null
                                || !lastAdded.getClassName().equals(
                                elements[i - 1].getClassName())) {
                    to      .append(elements[i-1].getClassName())
                            .append('.')
                            .append(elements[i-1].getMethodName())
                            .append('\n');
                }
            }
            
            if (i == 0) {
{'fraction_non_alphanumeric': 0.08610861086108611, 'fraction_numerical': 0.0058005800580058, 'mean_word_length': 1.5425883549453343, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6964557', 'n_tokens_mistral': 2461, 'n_tokens_neox': 2344, 'n_words': 635}