All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.boon.datarepo.impl.indexes.LookupIndexDefault Maven / Gradle / Ivy

Go to download

Simple opinionated Java for the novice to expert level Java Programmer. Low Ceremony. High Productivity. A real boon to Java to developers!

There is a newer version: 0.34
Show newest version
/*
 * Copyright 2013-2014 Richard M. Hightower
 * 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.
 *
 * __________                              _____          __   .__
 * \______   \ ____   ____   ____   /\    /     \ _____  |  | _|__| ____    ____
 *  |    |  _//  _ \ /  _ \ /    \  \/   /  \ /  \\__  \ |  |/ /  |/    \  / ___\
 *  |    |   (  <_> |  <_> )   |  \ /\  /    Y    \/ __ \|    <|  |   |  \/ /_/  >
 *  |______  /\____/ \____/|___|  / \/  \____|__  (____  /__|_ \__|___|  /\___  /
 *         \/                   \/              \/     \/     \/       \//_____/
 *      ____.                     ___________   _____    ______________.___.
 *     |    |____ ___  _______    \_   _____/  /  _  \  /   _____/\__  |   |
 *     |    \__  \\  \/ /\__  \    |    __)_  /  /_\  \ \_____  \  /   |   |
 * /\__|    |/ __ \\   /  / __ \_  |        \/    |    \/        \ \____   |
 * \________(____  /\_/  (____  / /_______  /\____|__  /_______  / / ______|
 *               \/           \/          \/         \/        \/  \/
 */

package org.boon.datarepo.impl.indexes;

import org.boon.Exceptions;
import org.boon.datarepo.LookupIndex;
import org.boon.datarepo.spi.SPIFactory;
import org.boon.core.Function;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * A really simple lookup index that uses a standard java.util.HashMap.
 *
 * @param   key to lookup
 * @param  value
 */
public class LookupIndexDefault implements LookupIndex {


    protected Function keyGetter;
    protected Function primaryKeyGetter;

    protected Map map;
    private Logger log = Logger.getLogger( LookupIndexDefault.class.getName() );
    protected boolean storeKeyInIndexOnly;
    private Function keyTransformer;

    protected int keyBucketSize = 3;


    public LookupIndexDefault( Class keyType ) {


        if ( log.isLoggable( Level.FINE ) ) {
            log.fine( String.format( "key type %s ", keyType.getName() ) );
        }

        if ( keyType == null ) {
            return;
        }
        map = SPIFactory.getMapCreatorFactory().get().createMap( keyType );

    }


    protected void addManyKeys( ITEM item, List keys ) {
        for ( KEY key : keys ) {
            if ( key != null ) {
                this.put( item, key );
            }
        }
    }

    @Override
    public boolean add( ITEM item ) {

        if ( log.isLoggable( Level.FINE ) ) {
            log.fine( String.format( "addObject item = %s", item ) );
        }

        KEY key = keyGetter.apply( item );
        if ( key == null ) {
            return false;
        }

        put( item, key );
        return true;

    }

    private void put( ITEM item, KEY key ) {

        MultiValue mv=null;
        Object primaryKey=null;

        try {

            if (log.isLoggable(Level.FINE)) {
                log.fine(String.format("put item = %s with key = %s ", item, key));
            }

            key = getKey(key);


            if (key instanceof Collection) {
                Collection collection = (Collection) key;

                for (Object keyComponent : collection) {

                    if (keyComponent == null) {
                        continue;
                    }
                    mv = map.get(keyComponent);
                    mv = mvCreateOrAddToMV(mv, item);
                    map.put((KEY) keyComponent, mv);
                }
                return;
            }


            mv = map.get(key);
            if (storeKeyInIndexOnly) {
                primaryKey = primaryKeyGetter.apply(item);

                mv = mvCreateOrAddToMV(mv, primaryKey);
            } else {
                mv = mvCreateOrAddToMV(mv, item);
            }

            map.put(key, mv);

        }catch (Exception ex) {
             Exceptions.handle(ex, "Problem putting item in lookup index, item=", item, "key=", key, "mv=", mv,
                     "primaryKey=", primaryKey);
        }
    }

    private MultiValue mvCreateOrAddToMV( MultiValue mv, Object obj ) {
        return MultiValue.add( mv, obj, keyBucketSize );
    }


    protected final void removeManyKeys( ITEM item, List keys ) {
        for ( KEY key : keys ) {
            if ( key != null ) {
                removeKey( item, key );
            }
        }
    }

    @Override
    public boolean delete( ITEM item ) {
        KEY key = keyGetter.apply( item );


        return removeKey( item, key );

    }

    private boolean removeKey( ITEM item, KEY key ) {
        key = getKey( key );

        if ( key == null ) {
            return false;
        }

        if (key instanceof  Collection) {
            Collection collection = (Collection) key;
            for (Object objKey : collection) {
                removeKey ( item, (KEY) objKey );
            }
        } else {
            MultiValue mv = map.get( key );

            if ( mv == null ) {
                return false;
            }

            mv = MultiValue.remove( mv, item );

            if ( mv == null ) {
                map.remove( key );
            }
        }
        return true;

    }


    public void setKeyGetter( Function keyGetter ) {
        Exceptions.requireNonNull( keyGetter, "keyGetter cannot be null" );
        this.keyGetter = keyGetter;
    }

    public void setPrimaryKeyGetter( Function keyGetter ) {
        Exceptions.requireNonNull( keyGetter, "keyGetter cannot be null" );
        storeKeyInIndexOnly = true;
        this.primaryKeyGetter = keyGetter;
    }

    @Override
    public List all() {

        if ( log.isLoggable( Level.FINE ) ) {
            log.fine( "all called" );
        }

        List results = new ArrayList<>( map.size() );
        for ( MultiValue values : map.values() ) {
            values.addTo( results );
        }
        return results;
    }

    @Override
    public int size() {
        return this.map.size();
    }

    @Override
    public Collection toCollection() {
        return ( Collection ) this.map.values();
    }


    @Override
    public ITEM get( KEY key ) {

        key = getKey( key );

        MultiValue mv = map.get( key );
        if ( mv == null ) {
            return null;
        } else {
            return ( ITEM ) mv.getValue();
        }
    }

    protected KEY getKey( KEY key ) {
        if ( keyTransformer != null ) {
            key = this.keyTransformer.apply( key );
        }
        return key;
    }


    public List getAll( KEY key ) {
        key = getKey( key );

        MultiValue mv = map.get( key );
        if ( mv == null ) {
            return null;
        } else {
            return mv.getValues();
        }
    }

    @Override
    public boolean deleteByKey( KEY key ) {
        key = getKey( key );

        this.map.remove( key );
        return true;
    }


    //TODO implement so we can store only primary keys in a index to make indexes smaller if
    //we ever decide to cache actual items
    @Override
    public boolean isPrimaryKeyOnly() {
        return storeKeyInIndexOnly;
    }

    @Override
    public void setInputKeyTransformer( Function func ) {
        this.keyTransformer = func;
    }

    @Override
    public void setBucketSize( int size ) {
        this.keyBucketSize = size;
    }

    @Override
    public void init() {
    }

    @Override
    public boolean has( KEY key ) {
        return this.map.containsKey( key );
    }


    @Override
    public void clear() {

        if ( log.isLoggable( Level.FINE ) ) {
            log.fine( "clear called" );
        }
        this.map.clear();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy