/*
* Copyright 2013
*
* @author Devin S. Olson (dolson@czarnowski.com)
*
* 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.openntf.domino.utils;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.TreeSet;
import java.util.Vector;
import lotus.domino.NotesException;
import org.openntf.domino.Document;
import org.openntf.domino.iterators.DocumentList;
/**
* CollectionUtils (Sets and Lists) utilities library
*
* @author Devin S. Olson (dolson@czarnowski.com)
*/
public enum CollectionUtils {
;
public static class ChainedIterable<T> implements Iterable<T> {
private final List<Iterable<T>> iterables_;
protected static class ChainedIterator<T> implements Iterator<T> {
private final List<Iterable<T>> iterables_;
private Iterator<T> currentIterator;
private int current = 0;
ChainedIterator(final List<Iterable<T>> iterables) {
iterables_ = iterables;
currentIterator = iterables_.get(0).iterator();
}
@Override
public void remove() {
currentIterator.remove();
}
@Override
public boolean hasNext() {
while (true) {
if (currentIterator.hasNext()) {
return true;
} else {
this.current++;
if (this.current >= iterables_.size())
break;
this.currentIterator = iterables_.get(this.current).iterator();
}
}
return false;
}
@Override
public T next() {
while (true) {
if (currentIterator.hasNext()) {
return currentIterator.next();
} else {
this.current++;
if (this.current >= iterables_.size())
break;
this.currentIterator = iterables_.get(current).iterator();
}
}
throw new NoSuchElementException();
}
}
public ChainedIterable(final Iterable<T>... iterables) {
if (iterables != null && iterables.length > 0) {
iterables_ = new ArrayList<Iterable<T>>(iterables.length);
for (Iterable<T> iterable : iterables) {
iterables_.add(iterable);
}
} else {
throw new IllegalArgumentException("Cannot pass a null or empty set of iterables to a ChainedIterable");
}
}
@Override
public Iterator<T> iterator() {
return new ChainedIterator<T>(iterables_);
}
}
/**
* Gets or generates an List of Strings from an Item on a Document
*
* @param source
* Document from which to get or generate the result.
*
* @param itemname
* Name of item from which to get the content
*
* @return List of Strings retrieved or generated from the input. Returns null if the document does not contain the item.
*
* @throws IllegalArgumentException
* if source document is null or itemname is blank or null.
*/
public static List<String> getListStrings(final Document source, final String itemname) {
if (null == source) {
throw new IllegalArgumentException("Source document is null");
}
if (Strings.isBlankString(itemname)) {
throw new IllegalArgumentException("ItemName is blank or null");
}
return (source.hasItem(itemname)) ? CollectionUtils.getListStrings(source.getItemValue(itemname)) : null;
}
/**
* Gets or generates an List of Strings from a Vector
*
* @param vector
* Vector from which to get or generate the result.
*
* @return List of Strings retrieved or generated from the input. Returns null on error.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static List<String> getListStrings(final Vector vector) {
return (null == vector) ? null : Collections.list(vector.elements());
}
/**
* Gets or generates an List of Strings from an AbstractCollection
*
* @param collection
* AbstractCollection from which to get or generate the result.
*
* @return List of Strings retrieved or generated from the input. Returns null on error.
*/
@SuppressWarnings({ "rawtypes", "cast" })
public static List<String> getListStrings(final AbstractCollection collection) {
if ((null != collection) && (collection.size() > 0)) {
final List<String> result = new ArrayList<String>();
if (collection.iterator().next() instanceof Object) {
// treat as an object
for (final Object o : collection) {
if (null != o) {
result.add(o.toString());
}
}
} else {
// treat as a primitive
final Iterator it = collection.iterator();
while (it.hasNext()) {
result.add(String.valueOf(it.next()));
}
}
return result;
}
return null;
}
/**
* Gets or generates an List of Strings from an AbstractMap
*
* @param map
* AbstractMap from which to get or generate the result. Only the Values will be retrieved, the Keys will are ignored.
*
* @return List of Strings retrieved or generated from the input. Returns null on error.
*/
@SuppressWarnings("rawtypes")
public static List<String> getListStrings(final AbstractMap map) {
return ((null != map) && (map.size() > 0)) ? CollectionUtils.getListStrings(map.values()) : null;
}
/**
* Gets or generates an List of Strings from a String
*
* @param string
* String from which to get or generate the result.
*
* @return List of Strings retrieved or generated from the input. Returns null on error.
*/
public static List<String> getListStrings(final String string) {
if (!Strings.isBlankString(string)) {
final List<String> result = new ArrayList<String>();
result.add(string);
return result;
}
return null;
}
/**
* Gets or generates an List of Strings from a array of Strings
*
* @param strings
* Array of Strings from which to get or generate the result.
*
* @return List of Strings retrieved or generated from the input. Returns null on error.
*/
public static List<String> getListStrings(final String[] strings) {
if ((null != strings) && (strings.length > 0)) {
final List<String> result = new ArrayList<String>();
for (final String s : strings) {
result.add(s);
}
return result;
}
return null;
}
/**
* Gets or generates an List of Strings from an Object
*
* @param object
* Object from which to get or generate the result. Attempts to retrieve the values from the object.
*
* @return List of Strings retrieved or generated from the input. Returns null on error.
*
*/
@SuppressWarnings("rawtypes")
public static List<String> getListStrings(final Object object) {
String classname = null;
try {
if (null != object) {
classname = object.getClass().getName();
if (object instanceof Vector) {
return CollectionUtils.getListStrings((Vector) object);
}
if (object instanceof AbstractCollection) {
return CollectionUtils.getListStrings((AbstractCollection) object);
}
if (object instanceof AbstractMap) {
return CollectionUtils.getListStrings((AbstractMap) object);
}
if (object instanceof String) {
return CollectionUtils.getListStrings((String) object);
}
if (object instanceof String[]) {
return CollectionUtils.getListStrings((String[]) object);
}
if (classname.equalsIgnoreCase("java.lang.String[]") || classname.equalsIgnoreCase("[Ljava.lang.String;")) {
return CollectionUtils.getListStrings((String[]) object);
}
if (classname.equalsIgnoreCase("java.lang.String")) {
return CollectionUtils.getListStrings((String) object);
}
throw new IllegalArgumentException("Unsupported Class:" + classname);
}
} catch (Exception e) {
DominoUtils.handleException(e);
}
return null;
}
/**
* Gets or generates a TreeSet of Strings from an Object
*
* @param object
* Object from which to get or generate the result. Attempts to retrieve the string values from the object.
*
* @return TreeSet of Strings retrieved or generated from the input. Returns null on error.
*
*/
public static TreeSet<String> getTreeSetStrings(final Object object) {
final List<String> al = CollectionUtils.getListStrings(object);
return (null == al) ? null : new TreeSet<String>(al);
}
/**
* Gets or generates an Array of Strings from an Object
*
* @param object
* Object from which to get or generate the result. Attempts to retrieve the string values from the object.
*
* @return Array of Strings retrieved or generated from the input. Returns null on error.
*
*/
public static String[] getStringArray(final Object object) {
final List<String> al = CollectionUtils.getListStrings(object);
return (null == al) ? null : al.toArray(new String[al.size()]);
}
/**
* Gets or generates an Array of Strings from an Object
*
* Result array will contain only unique values and will be sorted according to the String object's natural sorting method
*
* @param object
* Object from which to get or generate the result. Attempts to retrieve the string values from the object.
*
* @return Array of Strings retrieved or generated from the input. Returns null on error.
*
* @see java.lang.String#compareTo(String)
*
*/
public static String[] getSortedUnique(final Object object) {
final TreeSet<String> ts = CollectionUtils.getTreeSetStrings(object);
return ((null == ts) || (ts.size() < 1)) ? null : ts.toArray(new String[ts.size()]);
}
/**
* Compares two String[] objects
*
* Arguments are first compared by existence, then by # of elements, then by values.
*
* @param stringarray0
* First String[] to compare.
*
* @param stringarray1
* Second String[] to compare.
*
* @param descending
* flags indicating comparison order. true = descending, false = ascending.
*
* @return a negative integer, zero, or a positive integer indicating if the first object is less than, equal to, or greater than the
* second object.
*
* @see java.lang.Comparable#compareTo(Object)
* @see DominoUtils#LESS_THAN
* @see DominoUtils#EQUAL
* @see DominoUtils#GREATER_THAN
*/
public static int compareStringArrays(final String[] stringarray0, final String[] stringarray1, final boolean descending) {
if (null == stringarray0) {
return (null == stringarray1) ? DominoUtils.EQUAL : (descending) ? DominoUtils.GREATER_THAN : DominoUtils.LESS_THAN;
} else if (null == stringarray1) {
return (descending) ? DominoUtils.LESS_THAN : DominoUtils.GREATER_THAN;
}
if (stringarray0.length < stringarray1.length) {
return (descending) ? DominoUtils.GREATER_THAN : DominoUtils.LESS_THAN;
}
if (stringarray1.length < stringarray0.length) {
return (descending) ? DominoUtils.LESS_THAN : DominoUtils.GREATER_THAN;
}
for (int i = 0; i < stringarray0.length; i++) {
final int result = stringarray0[i].compareTo(stringarray1[i]);
if (DominoUtils.EQUAL != result) {
return (descending) ? -result : result;
}
}
return DominoUtils.EQUAL;
}
/**
* Compares two TreeSet<String> objects
*
* Arguments are first compared by existence, then by size, then by values.
*
* @param treeset0
* First TreeSet<String> to compare.
*
* @param treeset1
* Second TreeSet<String> to compare.
*
* @param descending
* flags indicating comparison order. true = descending, false = ascending.
*
* @return a negative integer, zero, or a positive integer indicating if the first object is less than, equal to, or greater than the
* second object.
*
* @see java.lang.Comparable#compareTo(Object)
* @see DominoUtils#LESS_THAN
* @see DominoUtils#EQUAL
* @see DominoUtils#GREATER_THAN
*/
public static int compareTreeSetStrings(final TreeSet<String> treeset0, final TreeSet<String> treeset1, final boolean descending) {
if (null == treeset0) {
return (null == treeset1) ? DominoUtils.EQUAL : (descending) ? DominoUtils.GREATER_THAN : DominoUtils.LESS_THAN;
} else if (null == treeset1) {
return (descending) ? DominoUtils.LESS_THAN : DominoUtils.GREATER_THAN;
}
if (treeset0.size() < treeset1.size()) {
return (descending) ? DominoUtils.GREATER_THAN : DominoUtils.LESS_THAN;
}
if (treeset1.size() < treeset0.size()) {
return (descending) ? DominoUtils.LESS_THAN : DominoUtils.GREATER_THAN;
}
// Compare as string arrays
return CollectionUtils.compareStringArrays(CollectionUtils.getStringArray(treeset0), CollectionUtils.getStringArray(treeset1),
descending);
}
/**
* Gets or generates a TreeSet containing Strings found in the source which begin with the prefix.
*
* Performs a case-insensitive search.
*
* @param source
* Object from which to attempt to extract and match the strings.
*
* @param prefix
* String which each extracted string must begin with.
*
* @return Strings found within source which begin with prefix.
*
* @see Strings#startsWithIgnoreCase(String, String)
*/
public static TreeSet<String> getTreeSetStringsBeginsWith(final Object source, final String prefix) {
final TreeSet<String> temp = CollectionUtils.getTreeSetStrings(source);
if ((null != temp) && (temp.size() > 0)) {
final TreeSet<String> result = new TreeSet<String>();
for (final String s : temp) {
if (Strings.startsWithIgnoreCase(s, prefix)) {
result.add(s);
}
}
return (result.size() > 0) ? result : null;
}
return null;
}
public static <T> Iterable<T> chain(final Iterable<T>... iterables) {
return new ChainedIterable<T>(iterables);
}
// /**
// * Convert a Document collection to Notes Collection
// *
// * @param collection
// * @return
// */
// public static org.openntf.domino.NoteCollection toLotusNoteCollection(final lotus.domino.DocumentCollection collection) {
// org.openntf.domino.NoteCollection result = null;
// if (collection instanceof org.openntf.domino.DocumentCollection) {
// org.openntf.domino.Database db = ((org.openntf.domino.DocumentCollection) collection).getAncestorDatabase();
// result = db.createNoteCollection(false);
// result.add(collection);
// } else if (collection != null) {
// // TODO Eh?
// org.openntf.domino.Database db = ((org.openntf.domino.DocumentCollection) collection).getAncestorDatabase();
// result = db.createNoteCollection(false);
// result.add(collection);
// }
// return result;
// }
/**
* Returns the Note IDs of the given (Notes) collection
*
* @param collection
* the DocumentCollection
* @return a array of NoteIDs
*/
public static int[] getNoteIDs(final lotus.domino.DocumentCollection collection) {
int[] result = null;
try {
if (collection instanceof DocumentList) {
result = ((DocumentList) collection).getNids();
} else if (collection.isSorted()) {
if (collection instanceof org.openntf.domino.DocumentCollection) {
org.openntf.domino.DocumentCollection ocoll = (org.openntf.domino.DocumentCollection) collection;
int size = ocoll.getCount();
result = new int[size];
int i = 0;
for (org.openntf.domino.Document doc : ocoll) {
result[i++] = Integer.valueOf(doc.getNoteID(), 16);
}
} else {
int size = collection.getCount();
result = new int[size];
lotus.domino.Document doc = collection.getFirstDocument();
lotus.domino.Document next = null;
int i = 0;
while (doc != null) {
next = collection.getNextDocument(doc);
result[i++] = Integer.valueOf(doc.getNoteID(), 16);
doc.recycle();
doc = next;
}
}
} else {
lotus.domino.Database db = collection.getParent();
lotus.domino.NoteCollection nc = db.createNoteCollection(false);
result = nc.getNoteIDs();
nc.recycle();
}
} catch (NotesException e) {
DominoUtils.handleException(e);
}
return result;
}
}