/*
* Copyright (c) 2010-2015 Evolveum
*
* 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.evolveum.midpoint.prism.xjc;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import org.apache.commons.lang.Validate;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.Collection;
import java.util.List;
/**
* @author lazyman
*
* Changed to extend AbstractList instead of ArrayList, as some functionality of ArrayList
* (e.g. its optimized Itr class) does not work with class (PrismContainerArrayList), as of Java7.
*
* TODO: account for concurrent structural modifications using modCount property
*/
public abstract class PrismContainerArrayList<T extends Containerable> extends AbstractList<T> implements Serializable {
private PrismContainer<T> container;
private PrismContainerValue<?> parent;
// For deserialization
public PrismContainerArrayList() {
}
public PrismContainerArrayList(PrismContainer<T> container) {
Validate.notNull(container);
this.container = container;
}
public PrismContainerArrayList(PrismContainer<T> container, PrismContainerValue<?> parent) {
Validate.notNull(container);
this.container = container;
this.parent = parent;
}
protected abstract PrismContainerValue getValueFrom(T t);
protected T createItemInternal(PrismContainerValue value) {
ComplexTypeDefinition concreteDef = value.getComplexTypeDefinition();
if (concreteDef != null &&
(container.getCompileTimeClass() == null ||
!container.getCompileTimeClass().equals(concreteDef.getCompileTimeClass()))) {
// the dynamic definition exists and the compile time class is different from the one at the container level
// ("different" here means it is a subclass)
// so we have to instantiate dynamically
T bean = null;
try {
bean = (T) concreteDef.getCompileTimeClass().newInstance();
} catch (InstantiationException|IllegalAccessException|RuntimeException e) {
throw new SystemException("Couldn't instantiate " + concreteDef.getCompileTimeClass());
}
bean.setupContainerValue(value);
return bean;
}
else {
// otherwise let's use the static (faster) way
return createItem(value);
}
}
protected abstract T createItem(PrismContainerValue value);
@Override
public T get(int i) {
testIndex(i);
return createItemInternal(getValues().get(i));
}
private List<PrismContainerValue<T>> getValues() {
return container.getValues();
}
@Override
public int size() {
return getValues().size();
}
private void testIndex(int i) {
if (i < 0 || i >= getValues().size()) {
throw new IndexOutOfBoundsException("Can't get index '" + i
+ "', values size is '" + getValues().size() + "'.");
}
}
@Override
public T remove(int i) {
testIndex(i);
PrismContainerValue value = getValues().get(i);
getValues().remove(i);
return createItemInternal(value);
}
@Override
public boolean removeAll(Collection<?> objects) {
boolean changed = false;
for (Object object : objects) {
if (!changed) {
changed = remove(object);
} else {
remove(object);
}
}
return changed;
}
@Override
public boolean remove(Object o) {
T t = (T) o;
PrismContainerValue value = getValueFrom(t);
return container.remove(value);
}
@Override
public boolean add(T t) {
PrismContainerValue value = getValueFrom(t);
try {
if (container.getParent() == null) {
parent.add(container);
}
return container.add(value);
} catch (SchemaException ex) {
throw new SystemException(ex.getMessage(), ex);
}
}
@Override
public boolean addAll(Collection<? extends T> ts) {
boolean changed = false;
for (T t : ts) {
if (!changed) {
changed = add(t);
} else {
add(t);
}
}
return changed;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
}