/*
* Copyright 2004-2009 the original author or authors.
*
* 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.compass.core.converter.mapping.osem.collection;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
import org.compass.core.mapping.osem.AbstractCollectionMapping;
import org.compass.core.spi.InternalCompassSession;
/**
* A lazy reference set. If no dirty operations are perfomed, will lazily load references from the
* search engine. Once a dirty operation is perfomed, will {@link #loadFully()}, and then all operations
* will be perfoemd on the loaded list.
*
* @author kimchy
*/
public class LazyReferenceSet extends AbstractSet implements LazyReferenceCollection {
private InternalCompassSession session;
private final ArrayList<LazyReferenceEntry> entries;
private Object[] objects;
private Set objectSet;
private AbstractCollectionMapping.CollectionType collectionType;
private boolean fullyLoaded = false;
public LazyReferenceSet(InternalCompassSession session, int size, AbstractCollectionMapping.CollectionType collectionType) {
this.session = session;
this.entries = new ArrayList<LazyReferenceEntry>(size);
this.collectionType = collectionType;
this.objects = new Object[size];
}
public void addLazyEntry(LazyReferenceEntry entry) {
entries.add(entry);
}
public Iterator iterator() {
if (fullyLoaded) {
return objectSet.iterator();
}
return new InternalIterator();
}
public int size() {
if (fullyLoaded) {
return objectSet.size();
}
return entries.size();
}
public boolean add(Object o) {
loadFully();
return objectSet.add(o);
}
public boolean remove(Object o) {
loadFully();
return objectSet.remove(o);
}
public boolean removeAll(Collection c) {
loadFully();
return objectSet.removeAll(c);
}
public boolean contains(Object o) {
if (fullyLoaded) {
return objectSet.contains(o);
}
return super.contains(o);
}
public boolean addAll(Collection c) {
loadFully();
return objectSet.addAll(c);
}
public void clear() {
fullyLoaded = true;
if (objectSet != null) {
objectSet.clear();
} else {
objectSet = createSet();
}
}
public boolean isFullyLoaded() {
return fullyLoaded;
}
public void loadFully() {
if (fullyLoaded) {
return;
}
objectSet = createSet();
for (Iterator it = iterator(); it.hasNext();) {
objectSet.add(it.next());
}
// we don't use objects or entries any more, we can null it.
objects = null;
entries.clear();
fullyLoaded = true;
}
private Set createSet() {
if (collectionType == AbstractCollectionMapping.CollectionType.SET) {
return new HashSet(entries.size());
} else if (collectionType == AbstractCollectionMapping.CollectionType.SORTED_SET) {
return new TreeSet();
} else if (collectionType == AbstractCollectionMapping.CollectionType.LINKED_HASH_SET) {
return new LinkedHashSet(entries.size());
} else {
throw new IllegalStateException("Should not happen, internal compass error");
}
}
private class InternalIterator implements Iterator {
private int cursor;
private Iterator dirtyIterator;
public boolean hasNext() {
if (dirtyIterator != null) {
return dirtyIterator.hasNext();
}
return cursor < entries.size();
}
public Object next() {
if (dirtyIterator != null) {
return dirtyIterator.next();
}
Object obj = objects[cursor];
if (obj == null) {
obj = session.get(entries.get(cursor).getAlias(), entries.get(cursor).getIds());
objects[cursor] = obj;
}
cursor++;
return obj;
}
public void remove() {
loadFully();
if (dirtyIterator != null) {
dirtyIterator.remove();
}
dirtyIterator = objectSet.iterator();
for (int i = 0; i < cursor; i++) {
dirtyIterator.next();
}
dirtyIterator.remove();
}
}
}