/*
* JBoss, Home of Professional Open Source
* Copyright 2015, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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 org.jboss.weld.bootstrap.enablement;
import static org.jboss.weld.util.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import javax.enterprise.inject.spi.Extension;
import org.jboss.weld.exceptions.UnsupportedOperationException;
import org.jboss.weld.logging.BootstrapLogger;
import org.jboss.weld.util.collections.ListView;
/**
*
* @author Martin Kouba
*
*/
abstract class EnablementListView extends ListView<Item, Class<?>> {
protected abstract ViewType getViewType();
protected abstract Extension getExtension();
private static final String ADD_OPERATION = "adds";
private static final String REMOVE_OPERATION = "removes";
private static final String SET_OPERATION = "sets";
private static final String RETAIN_OPERATION = "retains";
@SuppressWarnings("checkstyle:magicnumber")
private static final int DEFAULT_PRIORITY = javax.interceptor.Interceptor.Priority.APPLICATION + 500;
@Override
public boolean add(Class<?> element) {
checkNotNull(element);
List<Item> list = getDelegate();
synchronized (list) {
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), element, ADD_OPERATION, getViewType());
}
return list.add(createSource(element, list.isEmpty() ? null : list.get(list.size() - 1), null));
}
}
@Override
public Class<?> set(int index, Class<?> element) {
checkNotNull(element);
List<Item> list = getDelegate();
synchronized (list) {
if (index < 0 || index >= list.size()) {
throw new IndexOutOfBoundsException();
}
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), element, SET_OPERATION, getViewType());
}
return toView(getDelegate().set(index, createSource(element, list.get(index).getPriority())));
}
}
@Override
public void add(int index, Class<?> element) {
checkNotNull(element);
List<Item> list = getDelegate();
synchronized (list) {
if (index < 0 || index >= list.size()) {
throw new IndexOutOfBoundsException();
}
Item previous = (index > 0) ? list.get(index - 1) : null;
Item next = (index <= (list.size() - 1)) ? list.get(index) : null;
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), element, ADD_OPERATION, getViewType());
}
list.add(index, createSource(element, previous, next));
}
}
@Override
public Class<?> remove(int index) {
Item removedItem = getDelegate().remove(index);
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), removedItem.getClass(), REMOVE_OPERATION, getViewType());
}
return toView(removedItem);
}
@Override
public boolean removeAll(Collection<?> c) {
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), c, REMOVE_OPERATION, getViewType());
}
return getDelegate().removeAll(c);
}
@Override
public boolean remove(Object o) {
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), o, REMOVE_OPERATION, getViewType());
}
return getDelegate().remove(o);
}
@Override
public boolean retainAll(Collection<?> c) {
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), c, RETAIN_OPERATION, getViewType());
}
return getDelegate().retainAll(c);
}
@Override
public void clear() {
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), "", REMOVE_OPERATION + " all classes", getViewType());
}
getDelegate().clear();
}
@Override
protected Class<?> toView(Item source) {
return source.getJavaClass();
}
@Override
protected Item createSource(Class<?> view) {
throw new UnsupportedOperationException();
}
private Item createSource(Class<?> view, Item previous, Item next) {
return createSource(view, getPriority(previous, next));
}
private Item createSource(Class<?> view, int priority) {
return new Item(view, priority);
}
private int getPriority(Item previous, Item next) {
int priority;
if (previous == null && next == null) {
// No bounds
priority = DEFAULT_PRIORITY;
} else if (previous != null && next != null) {
int gap = (next.getPriority() - previous.getPriority());
if (gap == 0) {
// The items have the same priority
priority = next.getPriority();
} else if (gap == 1) {
// There is no gap - scale the priorities
for (Item item : getDelegate()) {
item.scalePriority();
}
priority = getPriority(previous, next);
} else {
priority = (gap / 2) + previous.getPriority();
}
} else if (previous != null) {
priority = previous.getPriority() + Item.ITEM_PRIORITY_SCALE_POWER;
} else {
priority = next.getPriority() - Item.ITEM_PRIORITY_SCALE_POWER;
}
return priority;
}
@Override
public ListIterator<Class<?>> listIterator() {
return new EnablementListViewIterator(getDelegate().listIterator());
}
@Override
public ListIterator<Class<?>> listIterator(int index) {
return new EnablementListViewIterator(getDelegate().listIterator(index));
}
class EnablementListViewIterator extends ListViewIterator {
public EnablementListViewIterator(ListIterator<Item> delegate) {
super(delegate);
}
/**
* The last item returned by a call to <code>next()</code> or <code>previous()</code>.
*/
private Item lastItem;
@Override
public Class<?> next() {
lastItem = delegate.next();
return EnablementListView.this.toView(lastItem);
}
@Override
public Class<?> previous() {
lastItem = delegate.previous();
return EnablementListView.this.toView(lastItem);
}
@Override
public void set(Class<?> clazz) {
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), clazz, SET_OPERATION, getViewType());
}
delegate.set(EnablementListView.this.createSource(clazz, lastItem.getPriority()));
}
@Override
public void add(Class<?> clazz) {
Item previous = hasPrevious() ? EnablementListView.this.getDelegate().get(previousIndex()) : null;
Item next = hasNext() ? EnablementListView.this.getDelegate().get(nextIndex()) : null;
if (getExtension() != null) {
BootstrapLogger.LOG.typeModifiedInAfterTypeDiscovery(getExtension(), clazz, ADD_OPERATION, getViewType());
}
delegate.add(EnablementListView.this.createSource(clazz, previous, next));
}
@Override
public void remove() {
if (getExtension() != null) {
BootstrapLogger.LOG
.typeModifiedInAfterTypeDiscovery(getExtension(), getDelegate().get(delegate.nextIndex()).getJavaClass(), REMOVE_OPERATION, getViewType());
}
delegate.remove();
}
}
enum ViewType {
ALTERNATIVES("getAlternatives()"),
INTERCEPTORS("getInterceptors()"),
DECORATORS("getDecorators()");
private final String name;
ViewType(String s) {
name = s;
}
public String toString() {
return this.name;
}
}
}