/* * Copyright 2013 serso aka se.solovyev * * 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. * * --------------------------------------------------------------------- * Contact details * * Email: se.solovyev@gmail.com * Site: http://se.solovyev.org */ package org.solovyev.common.math; import org.solovyev.common.collections.SortedList; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import java.util.ArrayList; import java.util.Comparator; import java.util.List; /** * User: serso * Date: 9/29/11 * Time: 4:57 PM */ public abstract class AbstractMathRegistry<T extends MathEntity> implements MathRegistry<T> { private static final MathEntityComparator<MathEntity> MATH_ENTITY_COMPARATOR = new MathEntityComparator<MathEntity>(); @GuardedBy("this") @Nonnull private static volatile Integer counter = 0; @GuardedBy("this") @Nonnull protected final SortedList<T> entities = SortedList.newInstance(new ArrayList<T>(30), MATH_ENTITY_COMPARATOR); @GuardedBy("this") @Nonnull protected final List<String> entityNames = new ArrayList<>(); @GuardedBy("this") @Nonnull protected final SortedList<T> systemEntities = SortedList.newInstance(new ArrayList<T>(30), MATH_ENTITY_COMPARATOR); protected AbstractMathRegistry() { } @Nonnull private static synchronized Integer count() { final Integer result = counter; counter++; return result; } @Nullable private static <E extends MathEntity> E removeByName(@Nonnull List<E> entities, @Nonnull String name) { for (int i = 0; i < entities.size(); i++) { final E entity = entities.get(i); if (entity.getName().equals(name)) { entities.remove(i); return entity; } } return null; } private static boolean areEqual(@Nullable Object l, @Nullable Object r) { return l != null ? l.equals(r) : r == null; } @Nonnull public List<T> getEntities() { synchronized (this) { return java.util.Collections.unmodifiableList(new ArrayList<T>(entities)); } } @Nonnull public List<T> getSystemEntities() { synchronized (this) { return java.util.Collections.unmodifiableList(new ArrayList<T>(systemEntities)); } } protected void add(@Nonnull T entity) { synchronized (this) { if (entity.isSystem()) { if (contains(entity.getName(), this.systemEntities)) { throw new IllegalArgumentException("Trying to add two system entities with same name: " + entity.getName()); } this.systemEntities.add(entity); } if (!contains(entity.getName(), this.entities)) { addEntity(entity, this.entities); this.entityNames.clear(); } } } private void addEntity(@Nonnull T entity, @Nonnull List<T> list) { assert Thread.holdsLock(this); entity.setId(count()); list.add(entity); } public T addOrUpdate(@Nonnull T entity) { synchronized (this) { final T existingEntity = entity.isIdDefined() ? getById(entity.getId()) : get(entity.getName()); if (existingEntity == null) { addEntity(entity, entities); entityNames.clear(); if (entity.isSystem()) { systemEntities.add(entity); } return entity; } else { existingEntity.copy(entity); this.entities.sort(); this.entityNames.clear(); this.systemEntities.sort(); return existingEntity; } } } public void remove(@Nonnull T entity) { synchronized (this) { if (!entity.isSystem()) { final T removed = removeByName(entities, entity.getName()); if (removed != null) { this.entityNames.clear(); } } } } @Nonnull public List<String> getNames() { synchronized (this) { if (entityNames.isEmpty()) { for (T entity : entities) { entityNames.add(entity.getName()); } } return entityNames; } } @Nullable public T get(@Nonnull final String name) { synchronized (this) { return get(name, entities); } } @Nullable private T get(@Nonnull String name, @Nonnull List<T> list) { for (int i = 0; i < list.size(); i++) { final T entity = list.get(i); if (areEqual(entity.getName(), name)) { return entity; } } return null; } public T getById(@Nonnull final Integer id) { synchronized (this) { for (T entity : entities) { if (areEqual(entity.getId(), id)) { return entity; } } return null; } } public boolean contains(@Nonnull final String name) { synchronized (this) { return contains(name, this.entities); } } private boolean contains(final String name, @Nonnull List<T> entities) { return get(name, entities) != null; } static class MathEntityComparator<T extends MathEntity> implements Comparator<T> { MathEntityComparator() { } public int compare(T l, T r) { int result = r.getName().length() - l.getName().length(); if (result == 0) { result = l.getName().compareTo(r.getName()); } return result; } } }