<commit_before>package com.couchbase.cblite;

import com.couchbase.cblite.auth.CBLAuthorizer;
import com.couchbase.cblite.auth.CBLFacebookAuthorizer;
import com.couchbase.cblite.auth.CBLPersonaAuthorizer;
import com.couchbase.cblite.internal.InterfaceAudience;
import com.couchbase.cblite.replicator.CBLPuller;
import com.couchbase.cblite.replicator.CBLPusher;
import com.couchbase.cblite.replicator.CBLReplicator;
import com.couchbase.cblite.support.FileDirUtils;
import com.couchbase.cblite.support.HttpClientFactory;
import com.couchbase.cblite.util.Log;

import org.codehaus.jackson.map.ObjectMapper;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Top-level CouchbaseLite object; manages a collection of databases as a CouchDB server does.
 */
public class CBLManager {

    private static final ObjectMapper mapper = new ObjectMapper();
    public static final String DATABASE_SUFFIX_OLD = ".touchdb";
    public static final String DATABASE_SUFFIX = ".cblite";
    public static final CBLManagerOptions DEFAULT_OPTIONS = new CBLManagerOptions(false, false);
    private static CBLManager sharedInstance;
    public static final String LEGAL_CHARACTERS = "[^a-z]{1,}[^a-z0-9_$()/+-]*$";


    private CBLManagerOptions options;
    private File directoryFile;
    private Map<String, CBLDatabase> databases;
    private List<CBLReplicator> replications;
    private ScheduledExecutorService workExecutor;
    private HttpClientFactory defaultHttpClientFactory;

    public static ObjectMapper getObjectMapper() {
        return mapper;
    }

    @InterfaceAudience.Public
    public CBLManager(File directoryFile) {
        this(directoryFile, DEFAULT_OPTIONS);
    }

    @InterfaceAudience.Public
    public CBLManager(File directoryFile, CBLManagerOptions options) {
        this.directoryFile = directoryFile;
        this.options = (options != null) ? options : DEFAULT_OPTIONS;
        this.databases = new HashMap<String, CBLDatabase>();
        this.replications = new ArrayList<CBLReplicator>();

        //create the directory, but don't fail if it already exists
        if(!directoryFile.exists()) {
            boolean result = directoryFile.mkdir();
            if(!result) {
                throw new RuntimeException("Unable to create directory " + directoryFile);
            }
        }

        upgradeOldDatabaseFiles(directoryFile);
        workExecutor = Executors.newSingleThreadScheduledExecutor();

    }

    @InterfaceAudience.Public
    public static CBLManager getSharedInstance() {
        return sharedInstance;
    }

    @InterfaceAudience.Public
    public synchronized static CBLManager createSharedInstance(File directoryFile, CBLManagerOptions options) {
        if (sharedInstance == null) {
            sharedInstance = new CBLManager(directoryFile, options);
        }
        return sharedInstance;
    }


    /**
     * Returns YES if the given name is a valid database name.
     * (Only the characters in "abcdefghijklmnopqrstuvwxyz0123456789_$()+-/" are allowed.)
     */
    @InterfaceAudience.Public
    public static boolean isValidDatabaseName(String databaseName) {
        if (databaseName.length() > 0 && databaseName.length() < 240 &&
                containsOnlyLegalCharacters(databaseName) &&
                Character.isLowerCase(databaseName.charAt(0))) {
            return true;
        }
        return databaseName.equals(CBLReplicator.REPLICATOR_DATABASE_NAME);
    }<commit_msg>Bring Manager API up to spec<commit_after>package com.couchbase.cblite;

import com.couchbase.cblite.auth.CBLAuthorizer;
import com.couchbase.cblite.auth.CBLFacebookAuthorizer;
import com.couchbase.cblite.auth.CBLPersonaAuthorizer;
import com.couchbase.cblite.internal.InterfaceAudience;
import com.couchbase.cblite.replicator.CBLPuller;
import com.couchbase.cblite.replicator.CBLPusher;
import com.couchbase.cblite.replicator.CBLReplicator;
import com.couchbase.cblite.support.FileDirUtils;
import com.couchbase.cblite.support.HttpClientFactory;
import com.couchbase.cblite.util.Log;

import org.codehaus.jackson.map.ObjectMapper;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Top-level CouchbaseLite object; manages a collection of databases as a CouchDB server does.
 */
public class CBLManager {

    private static final ObjectMapper mapper = new ObjectMapper();
    public static final String DATABASE_SUFFIX_OLD = ".touchdb";
    public static final String DATABASE_SUFFIX = ".cblite";
    public static final CBLManagerOptions DEFAULT_OPTIONS = new CBLManagerOptions(false, false);
    private static CBLManager sharedInstance;
    public static final String LEGAL_CHARACTERS = "[^a-z]{1,}[^a-z0-9_$()/+-]*$";


    private CBLManagerOptions options;
    private File directoryFile;
    private Map<String, CBLDatabase> databases;
    private List<CBLReplicator> replications;
    private ScheduledExecutorService workExecutor;
    private HttpClientFactory defaultHttpClientFactory;

    public static ObjectMapper getObjectMapper() {
        return mapper;
    }

    @InterfaceAudience.Public
    public CBLManager() {
        final String detailMessage = "Parameterless constructor is not a valid API call on Android. " +
                " Pure java version coming soon.";
        throw new RuntimeException(detailMessage);
    }

    @InterfaceAudience.Public
    public CBLManager(File directoryFile, CBLManagerOptions options) {
        this.directoryFile = directoryFile;
        this.options = (options != null) ? options : DEFAULT_OPTIONS;
        this.databases = new HashMap<String, CBLDatabase>();
        this.replications = new ArrayList<CBLReplicator>();

        //create the directory, but don't fail if it already exists
        if(!directoryFile.exists()) {
            boolean result = directoryFile.mkdir();
            if(!result) {
                throw new RuntimeException("Unable to create directory " + directoryFile);
            }
        }

        upgradeOldDatabaseFiles(directoryFile);
        workExecutor = Executors.newSingleThreadScheduledExecutor();

    }

    @InterfaceAudience.Public
    public static CBLManager getSharedInstance() {
        final String detailMessage = "getSharedInstance() is not a valid API call on Android. " +
                " Pure java version coming soon";
        throw new RuntimeException(detailMessage);
    }

    /**
     * Returns YES if the given name is a valid database name.
     * (Only the characters in "abcdefghijklmnopqrstuvwxyz0123456789_$()+-/" are allowed.)
     */
    @InterfaceAudience.Public
    public static boolean isValidDatabaseName(String databaseName) {
        if (databaseName.length() > 0 && databaseName.length() < 240 &&
                containsOnlyLegalCharacters(databaseName) &&
                Character.isLowerCase(databaseName.charAt(0))) {
            return true;
        }
        return databaseName.equals(CBLReplicator.REPLICATOR_DATABASE_NAME);
    }
{'fraction_non_alphanumeric': 0.08874984037798493, 'fraction_numerical': 0.004597114033967565, 'mean_word_length': 3.695443645083933, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '1210592', 'n_tokens_mistral': 2268, 'n_tokens_neox': 2187, 'n_words': 513}