org.lenskit.data.entities.Entities.java Source code

Java tutorial

Introduction

Here is the source code for org.lenskit.data.entities.Entities.java

Source

/*
 * LensKit, an open source recommender systems toolkit.
 * Copyright 2010-2014 LensKit Contributors.  See CONTRIBUTORS.md.
 * Work on LensKit has been funded by the National Science Foundation under
 * grants IIS 05-34939, 08-08692, 08-12148, and 10-17697.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.lenskit.data.entities;

import com.google.common.base.*;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Longs;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.lenskit.util.keys.KeyExtractor;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentHashMap;

public final class Entities {
    private static ConcurrentHashMap<Class<?>, Optional<Constructor<? extends EntityBuilder>>> BUILDER_CTOR_CACHE = new ConcurrentHashMap<>();

    private Entities() {
    }

    /**
     * Create a new bare entity.
     * @param type The bare entity.
     * @param id The entity ID.
     * @return An entity.
     */
    public static Entity create(EntityType type, long id) {
        return new BareEntity(type, id);
    }

    /**
     * Create a new basic entity builder.
     * @param type The entity type.
     * @return The entity builder.
     */
    public static EntityBuilder newBuilder(EntityType type) {
        return new BasicEntityBuilder(type);
    }

    /**
     * Create a new basic entity builder.
     * @param id The entity ID.
     * @return The entity builder.
     */
    public static EntityBuilder newBuilder(EntityType type, long id) {
        return newBuilder(type).setId(id);
    }

    /**
     * Create a new entity builder that is initialized with a copy of an entity.
     * @param e The entity.
     * @return An entity builder initialized to build a copy of {@code e}.
     */
    public static EntityBuilder copyBuilder(Entity e) {
        EntityBuilder eb = newBuilder(e.getType(), e.getId());
        for (TypedName a : e.getTypedAttributeNames()) {
            eb.setAttribute(a, e.get(a));
        }
        return eb;
    }

    /**
     * Create a predicate that filters events for an entity type.
     * @param type The entity type.
     * @return A predicate matching entities of type `type`.
     */
    public static Predicate<Entity> typePredicate(final EntityType type) {
        return new Predicate<Entity>() {
            @Override
            public boolean apply(@Nullable Entity input) {
                return (input != null) && input.getType().equals(type);
            }
        };
    }

    /**
     * Create a predicate that filters events for an ID.
     * @param id The ID sought.
     * @return A predicate matching entities with id `id`.
     */
    public static Predicate<Entity> idPredicate(final long id) {
        return new Predicate<Entity>() {
            @Override
            public boolean apply(@Nullable Entity input) {
                return (input != null) && input.getId() == id;
            }
        };
    }

    /**
     * Return an ordering over entities that sorts them by ID.
     * @return An ordering over entities by ID.
     */
    public static Ordering<Entity> idOrdering() {
        return ID_ORDER;
    }

    /**
     * Key extractor that keys entities by ID.
     * @return A key extractor that returns entities' IDs.
     */
    public static KeyExtractor<Entity> idKeyExtractor() {
        return ID_KEY_EX;
    }

    /**
     * Function that extracts an entity's type.
     * @return A function that extracts an entity's type.
     */
    public static Function<Entity, EntityType> extractType() {
        return EntityTypeFunc.INSTANCE;
    }

    public static <T> Function<Entity, T> attributeValueFunction(final TypedName<T> name) {
        return new Function<Entity, T>() {
            @Nullable
            @Override
            public T apply(@Nullable Entity input) {
                return input == null ? null : input.maybeGet(name);
            }
        };
    }

    /**
     * Project an entity to a target view type.
     * @param e The entity to project.
     * @param viewClass The view type.
     * @param <E> The view type.
     * @return The projected entity.
     */
    public static <E extends Entity> E project(@Nonnull Entity e, @Nonnull Class<E> viewClass) {
        if (viewClass.isInstance(e)) {
            return viewClass.cast(e);
        } else {
            Optional<Constructor<? extends EntityBuilder>> ctor = BUILDER_CTOR_CACHE.get(viewClass);
            if (ctor == null) {
                BuiltBy bb = viewClass.getAnnotation(BuiltBy.class);
                if (bb != null) {
                    Class<? extends EntityBuilder> ebClass = bb.value();
                    Constructor<? extends EntityBuilder> found = ConstructorUtils.getAccessibleConstructor(ebClass,
                            EntityType.class);
                    ctor = Optional.<Constructor<? extends EntityBuilder>>fromNullable(found);
                } else {
                    ctor = Optional.absent();
                }
                BUILDER_CTOR_CACHE.put(viewClass, ctor);
            }

            if (ctor.isPresent()) {
                EntityBuilder builder = null;
                try {
                    builder = ctor.get().newInstance(e.getType());
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
                    throw new RuntimeException("cannot invoke " + ctor.get(), ex);
                }
                for (Attribute<?> attr : e.getAttributes()) {
                    builder.setAttribute(attr);
                }
                return viewClass.cast(builder.build());
            } else {
                throw new IllegalArgumentException(
                        "entity type " + e.getClass() + " cannot be projected to " + viewClass);
            }
        }
    }

    /**
     * Create a projection function that maps entities to a new view.
     * @param viewClass The target view class type.
     * @param <E> The entity type.
     * @return A function that will project entities.
     */
    @SuppressWarnings("unchecked")
    public static <E extends Entity> Function<Entity, E> projection(final Class<E> viewClass) {
        if (viewClass.equals(Entity.class)) {
            return (Function) Functions.identity();
        } else {
            return new Function<Entity, E>() {
                @Nullable
                @Override
                public E apply(@Nullable Entity input) {
                    assert input != null;
                    return project(input, viewClass);
                }
            };
        }
    }

    /**
     * Extract the ID from an entity as its key.
     */
    private static class IdKeyEx implements KeyExtractor<Entity> {
        @Override
        public long getKey(Entity obj) {
            return obj.getId();
        }
    }

    private static class IdOrder extends Ordering<Entity> {
        @Override
        public int compare(@Nullable Entity left, @Nullable Entity right) {
            return Longs.compare(left.getId(), right.getId());
        }
    }

    private static Ordering<Entity> ID_ORDER = new IdOrder();
    private static KeyExtractor<Entity> ID_KEY_EX = new IdKeyEx();

    private static enum EntityTypeFunc implements Function<Entity, EntityType> {
        INSTANCE;

        @Nullable
        @Override
        public EntityType apply(@Nullable Entity input) {
            Preconditions.checkNotNull(input);
            return input.getType();
        }
    }
}