<commit_before>/*
Copyright 2017 <NAME>

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.mcherm.invalidationqueue;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;


/**
 * An implementation of the ComponentCache interface, using the provided Storage, which provides
 * the underlying key-value storage. Storage keys will be the session id, a colon (":"), and then
 * the field name.
 */
public class ComponentCacheImpl<CIE extends CacheInvalidationEvent, SD extends SessionData> implements ComponentCache<CIE>, StatelessSessionBean {
    private final String ENTRIES_JSON_FIELD_NAME = "entries";
    private final String NAME_JSON_FIELD_NAME = "name";
    private final String TYPE_JSON_FIELD_NAME = "type";
    private final String EVENTS_JSON_FIELD_NAME = "invalidatingEvents";
    private final String REFRESH_FUNCTION_JSON_FIELD_NAME = "refreshFunction";

    private static final String PLACE_IN_QUEUE_ENTRY_NAME = "invalidationqueuePosition";


    /**
     * An immutable data object containing the metadata about a single entry in the component
     * cache. It contains things like the field's name, type, the list of events that would render
     * the current value invalid, and (optionally), the function to call to obtain an up-to-date
     * value for the field.
     */
    protected static class EntryMetadata<CIE2 extends CacheInvalidationEvent> {
        private final String name;
        private final Class type;
        private final Set<CIE2> invalidators;
        private final Callable<String> refreshFunction;

        /** Constructor. */
        public EntryMetadata(String name, Class type, Set<CIE2> invalidators, Callable<String> refreshFunction) {
            this.name = name;
            this.type = type;
            this.invalidators = Collections.unmodifiableSet(invalidators);
            this.refreshFunction = refreshFunction;
        }

        /**
         * Returns the name of the entry.
         */
        public String getName() {
            return name;
        }

        // FIXME: Do for real and doc it if it works
        public Class getType() {
            return type;
        }

        /**
         * Retrieves the set of events which would render this field invalid. If any of the
         * events have occurred, then the ComponentCache will clear the entry.
         */
        public Set<CIE2> getInvalidators() {
            return invalidators;
        }

        /**
         * If there is a function to call which will retrieve the value of this field on-demand,
         * then this returns it. If not, then this returns null.
         */
        public Callable<String> getRefreshFunction() {
            return refreshFunction;
        }
    }


    private final ObjectMapper objectMapper;
    private final StorageMechanism storageMechanism;
    private final SD sessionData;
    private final CacheInvalidationQueue<CIE> cacheInvalidationQueue;
    private final Map<String,EntryMetadata<CIE>> entryMetadataMap;


    /**<commit_msg>Documentation of how you can now specify field types.<commit_after>/*
Copyright 2017 <NAME>

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.mcherm.invalidationqueue;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;


/**
 * An implementation of the ComponentCache interface, using the provided Storage, which provides
 * the underlying key-value storage. Storage keys will be the session id, a colon (":"), and then
 * the field name.
 */
public class ComponentCacheImpl<CIE extends CacheInvalidationEvent, SD extends SessionData> implements ComponentCache<CIE>, StatelessSessionBean {
    private final String ENTRIES_JSON_FIELD_NAME = "entries";
    private final String NAME_JSON_FIELD_NAME = "name";
    private final String TYPE_JSON_FIELD_NAME = "type";
    private final String EVENTS_JSON_FIELD_NAME = "invalidatingEvents";
    private final String REFRESH_FUNCTION_JSON_FIELD_NAME = "refreshFunction";

    private static final String PLACE_IN_QUEUE_ENTRY_NAME = "invalidationqueuePosition";


    /**
     * An immutable data object containing the metadata about a single entry in the component
     * cache. It contains things like the field's name, type, the list of events that would render
     * the current value invalid, and (optionally), the function to call to obtain an up-to-date
     * value for the field.
     */
    protected static class EntryMetadata<CIE2 extends CacheInvalidationEvent> {
        private final String name;
        private final Class type;
        private final Set<CIE2> invalidators;
        private final Callable<String> refreshFunction;

        /**
         * Constructor.
         *
         * @param name the name of the field, which will be passed to the <code>storeEntry()</code>,
         *             <code>getEntry()</code>, and <code>clearEntry()</code> methods on the cache.
         * @param type the type of the object that will be stored in this field. Must be either
         *             <code>java.lang.String</code> or anything which can be serialized using the
         *             Jackson library.
         * @param invalidators a set of events which, if they occur, will invalidate any cached
         *                     value, so after such an event the cache will effectively be cleared.
         * @param refreshFunction a function which can be called to load in a new value for this
         *                        entry if no value is currently available, or null if there is
         *                        no such function. For fields where this is null, the <code>getEntry()</code>
         *                        method can sometimes return null even if a value had previously
         *                        been cached, due to invalidation or due to the cache being
         *                        unreliable.
         */
        public EntryMetadata(String name, Class type, Set<CIE2> invalidators, Callable<String> refreshFunction) {
            this.name = name;
            this.type = type;
            this.invalidators = Collections.unmodifiableSet(invalidators);
            this.refreshFunction = refreshFunction;
        }

        /**
         * Returns the name of the entry.
         */
        public String getName() {
            return name;
        }

        /**
         * Returns the type of data that will be stored in the field. This will be be either
         * <code>java.lang.String</code> or anything which can be serialized using the
         * Jackson library.
         */
        public Class getType() {
            return type;
        }

        /**
         * Retrieves the set of events which would render this field invalid. If any of the
         * events have occurred, then the ComponentCache will clear the entry.
         */
        public Set<CIE2> getInvalidators() {
            return invalidators;
        }

        /**
         * If there is a function to call which will retrieve the value of this field on-demand,
         * then this returns it. If not, then this returns null.
         */
        public Callable<String> getRefreshFunction() {
            return refreshFunction;
        }
    }


    private final ObjectMapper objectMapper;
    private final StorageMechanism storageMechanism;
    private final SD sessionData;
    private final CacheInvalidationQueue<CIE> cacheInvalidationQueue;
    private final Map<String,EntryMetadata<CIE>> entryMetadataMap;


    /**
{'fraction_non_alphanumeric': 0.06902201740911418, 'fraction_numerical': 0.002457757296466974, 'mean_word_length': 2.9048380647740903, 'pattern_counts': {'":': 2, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6024205', 'n_tokens_mistral': 2467, 'n_tokens_neox': 2396, 'n_words': 953}