/*
* Copyright (c) 2010-2014 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.model.impl.lens;
import com.evolveum.midpoint.common.crypto.CryptoUtil;
import com.evolveum.midpoint.prism.ConsistencyCheckScope;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectDeltaWaveType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectDeltaWavesType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import java.io.Serializable;
import java.util.*;
/**
* @author semancik
*
*/
public class ObjectDeltaWaves<O extends ObjectType> implements List<ObjectDelta<O>>, DebugDumpable, Serializable {
private List<ObjectDelta<O>> waves = new ArrayList<ObjectDelta<O>>();
/**
* Get merged deltas from all the waves.
*/
public ObjectDelta<O> getMergedDeltas() throws SchemaException {
return getMergedDeltas(null, -1);
}
/**
* Get merged deltas from the waves up to maxWave (including). Optional initial delta may be supplied.
* Negative maxWave means to merge all available waves.
*/
public ObjectDelta<O> getMergedDeltas(ObjectDelta<O> initialDelta, int maxWave) throws SchemaException {
ObjectDelta<O> merged = null;
if (initialDelta != null) {
merged = initialDelta.clone();
}
int waveNum = 0;
for (ObjectDelta<O> delta: waves) {
if (delta == null) {
continue;
}
if (merged == null) {
merged = delta.clone();
} else {
merged.merge(delta);
}
if (maxWave >= 0 && waveNum >= maxWave) {
break;
}
}
return merged;
}
public void setOid(String oid) {
for (ObjectDelta<O> delta: waves) {
if (delta == null) {
continue;
}
delta.setOid(oid);
}
}
public void checkConsistence(boolean requireOid, String shortDesc) {
for (int wave = 0; wave < waves.size(); wave++) {
ObjectDelta<O> delta = waves.get(wave);
if (delta == null) {
continue;
}
try {
delta.checkConsistence(requireOid, true, true, ConsistencyCheckScope.THOROUGH);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage()+"; in "+shortDesc+", wave "+wave, e);
} catch (IllegalStateException e) {
throw new IllegalStateException(e.getMessage()+"; in "+shortDesc+", wave "+wave, e);
}
}
}
public void normalize() {
if (waves != null) {
for (ObjectDelta<O> wave: waves) {
if (wave != null) {
wave.normalize();
}
}
}
}
public ObjectDeltaWaves<O> clone() {
ObjectDeltaWaves<O> clone = new ObjectDeltaWaves<O>();
copyValues(clone);
return clone;
}
protected void copyValues(ObjectDeltaWaves<O> clone) {
for (ObjectDelta<O> thisWave: this.waves) {
if (thisWave != null) {
clone.waves.add(thisWave.clone());
} else {
clone.waves.add(null);
}
}
}
public void adopt(PrismContext prismContext) throws SchemaException {
for (ObjectDelta<O> thisWave: this.waves) {
if (thisWave != null) {
prismContext.adopt(thisWave);
}
}
}
// DELEGATED METHODS (with small tweaks)
/* (non-Javadoc)
* @see java.util.List#size()
*/
@Override
public int size() {
return waves.size();
}
/* (non-Javadoc)
* @see java.util.List#isEmpty()
*/
@Override
public boolean isEmpty() {
return waves.isEmpty();
}
/* (non-Javadoc)
* @see java.util.List#contains(java.lang.Object)
*/
@Override
public boolean contains(Object o) {
return waves.contains(o);
}
/* (non-Javadoc)
* @see java.util.List#iterator()
*/
@Override
public Iterator<ObjectDelta<O>> iterator() {
return waves.iterator();
}
/* (non-Javadoc)
* @see java.util.List#toArray()
*/
@Override
public Object[] toArray() {
return waves.toArray();
}
/* (non-Javadoc)
* @see java.util.List#toArray(T[])
*/
@Override
public <T> T[] toArray(T[] a) {
return waves.toArray(a);
}
/* (non-Javadoc)
* @see java.util.List#add(java.lang.Object)
*/
@Override
public boolean add(ObjectDelta<O> e) {
return waves.add(e);
}
/* (non-Javadoc)
* @see java.util.List#remove(java.lang.Object)
*/
@Override
public boolean remove(Object o) {
return waves.remove(o);
}
/* (non-Javadoc)
* @see java.util.List#containsAll(java.util.Collection)
*/
@Override
public boolean containsAll(Collection<?> c) {
return waves.containsAll(c);
}
/* (non-Javadoc)
* @see java.util.List#addAll(java.util.Collection)
*/
@Override
public boolean addAll(Collection<? extends ObjectDelta<O>> c) {
return waves.addAll(c);
}
/* (non-Javadoc)
* @see java.util.List#addAll(int, java.util.Collection)
*/
@Override
public boolean addAll(int index, Collection<? extends ObjectDelta<O>> c) {
return waves.addAll(index, c);
}
/* (non-Javadoc)
* @see java.util.List#removeAll(java.util.Collection)
*/
@Override
public boolean removeAll(Collection<?> c) {
return waves.removeAll(c);
}
/* (non-Javadoc)
* @see java.util.List#retainAll(java.util.Collection)
*/
@Override
public boolean retainAll(Collection<?> c) {
return waves.retainAll(c);
}
/* (non-Javadoc)
* @see java.util.List#clear()
*/
@Override
public void clear() {
waves.clear();
}
/* (non-Javadoc)
* @see java.util.List#get(int)
*/
@Override
public ObjectDelta<O> get(int index) {
if (index >= waves.size()) {
return null;
}
return waves.get(index);
}
/* (non-Javadoc)
* @see java.util.List#set(int, java.lang.Object)
*/
@Override
public ObjectDelta<O> set(int index, ObjectDelta<O> element) {
if (index >= waves.size()) {
for (int i = waves.size(); i < index; i++) {
waves.add(null);
}
waves.add(element);
return element;
}
return waves.set(index, element);
}
/* (non-Javadoc)
* @see java.util.List#add(int, java.lang.Object)
*/
@Override
public void add(int index, ObjectDelta<O> element) {
waves.add(index, element);
}
/* (non-Javadoc)
* @see java.util.List#remove(int)
*/
@Override
public ObjectDelta<O> remove(int index) {
return waves.remove(index);
}
/* (non-Javadoc)
* @see java.util.List#indexOf(java.lang.Object)
*/
@Override
public int indexOf(Object o) {
return waves.indexOf(o);
}
/* (non-Javadoc)
* @see java.util.List#lastIndexOf(java.lang.Object)
*/
@Override
public int lastIndexOf(Object o) {
return waves.lastIndexOf(o);
}
/* (non-Javadoc)
* @see java.util.List#listIterator()
*/
@Override
public ListIterator<ObjectDelta<O>> listIterator() {
return waves.listIterator();
}
/* (non-Javadoc)
* @see java.util.List#listIterator(int)
*/
@Override
public ListIterator<ObjectDelta<O>> listIterator(int index) {
return waves.listIterator(index);
}
/* (non-Javadoc)
* @see java.util.List#subList(int, int)
*/
@Override
public List<ObjectDelta<O>> subList(int fromIndex, int toIndex) {
return waves.subList(fromIndex, toIndex);
}
// DUMP
@Override
public String debugDump() {
return debugDump(0);
}
public String dump(boolean showTriples) {
return debugDump(0, showTriples);
}
@Override
public String debugDump(int indent) {
return debugDump(indent, true);
}
public String debugDump(int indent, boolean showTriples) {
StringBuilder sb = new StringBuilder();
DebugUtil.indentDebugDump(sb, indent);
sb.append("ObjectDeltaWaves:");
if (waves.isEmpty()) {
sb.append(" empty");
return sb.toString();
}
if (waves.size() == 1) {
sb.append(" single wave\n");
if (waves.get(0) != null) {
sb.append(waves.get(0).debugDump(indent + 1));
} else {
DebugUtil.indentDebugDump(sb, indent + 1);
sb.append("null\n");
}
} else {
sb.append(waves.size()).append(" waves");
for (int wave = 0; wave < waves.size(); wave++) {
sb.append("\n");
ObjectDelta<O> delta = waves.get(wave);
DebugUtil.indentDebugDump(sb, indent + 1);
sb.append("wave ").append(wave).append(":");
if (delta == null) {
sb.append(" null");
} else {
sb.append("\n");
sb.append(delta.debugDump(indent + 2));
}
}
}
return sb.toString();
}
@Override
public String toString() {
return "ObjectDeltaWaves(" + waves + ")";
}
public ObjectDeltaWavesType toObjectDeltaWavesType() throws SchemaException {
ObjectDeltaWavesType objectDeltaWavesType = new ObjectDeltaWavesType();
for (int i = 0; i < waves.size(); i++) {
ObjectDelta wave = waves.get(i);
if (wave != null) {
ObjectDeltaWaveType objectDeltaWaveType = new ObjectDeltaWaveType();
objectDeltaWaveType.setNumber(i);
objectDeltaWaveType.setDelta(DeltaConvertor.toObjectDeltaType(wave));
objectDeltaWavesType.getWave().add(objectDeltaWaveType);
}
}
return objectDeltaWavesType;
}
// don't forget to apply provisioning definitions to resulting deltas (it's the client responsibility)
public static <O extends ObjectType> ObjectDeltaWaves<O> fromObjectDeltaWavesType(ObjectDeltaWavesType secondaryDeltas, PrismContext prismContext) throws SchemaException {
if (secondaryDeltas == null) {
return null;
}
ObjectDeltaWaves<O> retval = new ObjectDeltaWaves<>();
int max = 0;
for (ObjectDeltaWaveType odwt : secondaryDeltas.getWave()) {
if (odwt.getNumber() > max) {
max = odwt.getNumber();
}
}
ObjectDelta<O>[] wavesAsArray = new ObjectDelta[max+1];
for (ObjectDeltaWaveType odwt : secondaryDeltas.getWave()) {
wavesAsArray[odwt.getNumber()] = DeltaConvertor.createObjectDelta(odwt.getDelta(), prismContext);
}
for (int i = 0; i <= max; i++) {
retval.waves.add(wavesAsArray[i]);
}
return retval;
}
public void checkEncrypted(String shortDesc) {
for (int wave = 0; wave < waves.size(); wave++) {
ObjectDelta<O> delta = waves.get(wave);
if (delta == null) {
continue;
}
try {
CryptoUtil.checkEncrypted(delta);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage()+"; in "+shortDesc+", wave "+wave, e);
} catch (IllegalStateException e) {
throw new IllegalStateException(e.getMessage()+"; in "+shortDesc+", wave "+wave, e);
}
}
}
}