/*
* 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 java.util.AbstractList;
import java.util.Collection;
import javax.xml.namespace.QName;
import org.apache.commons.lang.Validate;
import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.util.JAXBUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
/**
* A list used for JAXB getAny() methods.
* It is not used for normal prism operation, not even if compilte-time (JAXB) classes are used.
* It is quite a bad way to use getAny() methods from the JAXB classes, it is much better to use
* prism facet instead. However we need this to be fully JAXB compliant and therefore support
* XML marshalling/unmarshalling. This is important e.g. for JAX-WS.
*
* @author Radovan Semancik
*/
public class AnyArrayList<C extends Containerable> extends AbstractList<Object> {
private PrismContainerValue<C> containerValue;
public AnyArrayList(PrismContainerValue<C> containerValue) {
Validate.notNull(containerValue, "Container value must not be null.");
this.containerValue = containerValue;
}
@Override
public int size() {
if (isSchemaless()) {
throw new UnsupportedOperationException("Definition-less containers are not supported any more.");
} else {
// Each item and each value are presented as one list entry
// (multi-valued items are represented as multiple occurrences of the same element)
int size = 0;
if (containerValue.isEmpty()){
return size;
}
for (Item<?,?> item: containerValue.getItems()) {
size += item.getValues().size();
}
return size;
}
}
@Override
public Object get(int index) {
if (isSchemaless()) {
throw new UnsupportedOperationException("Definition-less containers are not supported any more.");
} else {
if (containerValue != null) {
for (Item<?,?> item : containerValue.getItems()) {
if (index < item.getValues().size()) {
return asElement(item.getValue(index));
} else {
index -= item.getValues().size();
}
}
throw new IndexOutOfBoundsException();
}
return null; //TODO: is this OK??
}
}
@Override
public boolean addAll(Collection<? extends Object> elements) {
Validate.notNull(elements, "Collection must not be null.");
if (elements.isEmpty()) {
return false;
}
for (Object element : elements) {
add(element);
}
return true;
}
@Override
public boolean addAll(int i, Collection<? extends Object> elements) {
return addAll(elements);
}
@Override
public boolean add(Object element) {
try {
return containerValue.addRawElement(element);
} catch (SchemaException e) {
QName elementName = JAXBUtil.getElementQName(element);
throw new IllegalArgumentException("Element "+elementName+" cannot be added because is violates object schema: "+e.getMessage(),e);
}
}
@Override
public void add(int i, Object element) {
add(element);
}
@Override
public Object remove(int index) {
if (isSchemaless()) {
throw new UnsupportedOperationException("Definition-less containers are not supported any more.");
} else {
for (Item<?,?> item: containerValue.getItems()) {
if (index < item.getValues().size()) {
item.remove(index);
} else {
index -= item.getValues().size();
}
}
throw new IndexOutOfBoundsException();
}
}
@Override
public boolean remove(Object element) {
if (isSchemaless()) {
return containerValue.removeRawElement(element);
} else {
try {
return containerValue.deleteRawElement(element);
} catch (SchemaException e) {
QName elementName = JAXBUtil.getElementQName(element);
throw new IllegalArgumentException("Element "+elementName+" cannot be removed because is violates object schema: "+e.getMessage(),e);
}
}
}
@Override
public boolean removeAll(Collection<?> objects) {
boolean changed = false;
for (Object object : objects) {
if (!changed) {
changed = remove(object);
} else {
remove(object);
}
}
return changed;
}
private boolean isSchemaless() {
return containerValue.getComplexTypeDefinition() == null;
}
private PrismContainer<C> getContainer() {
return containerValue.getContainer();
}
private PrismContext getPrismContext() {
return getContainer().getPrismContext();
}
private Object asElement(PrismValue itemValue) {
PrismContext prismContext = containerValue.getPrismContext();
if (prismContext == null) {
throw new IllegalStateException("prismContext is null in " + containerValue);
}
try {
return prismContext.getJaxbDomHack().toAny(itemValue);
} catch (SchemaException e) {
throw new SystemException("Unexpected schema problem: "+e.getMessage(),e);
}
}
}