/* * Copyright (c) 2010-2016 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.util; import org.jetbrains.annotations.NotNull; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConstants; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import java.io.*; import java.nio.channels.FileChannel; import java.util.*; import java.util.Map.Entry; import java.util.function.Function; import java.util.stream.Stream; /** * @author semancik * */ public class MiscUtil { private static final int BUFFER_SIZE = 2048; private static DatatypeFactory df = null; static { try { df = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException dce) { throw new IllegalStateException("Exception while obtaining Datatype Factory instance", dce); } } public static <T> Collection<T> union(Collection<T>... sets) { Set<T> resultSet = new HashSet<>(); for (Collection<T> set: sets) { if (set != null) { resultSet.addAll(set); } } return resultSet; } public static <T> Collection<? extends T> unionExtends(Collection<? extends T>... sets) { Set<T> resultSet = new HashSet<T>(); for (Collection<? extends T> set: sets) { if (set != null) { resultSet.addAll(set); } } return resultSet; } public static <T> boolean listEquals(List<T> a, List<T> b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } if (a.size() != b.size()) { return false; } for (int i = 0; i < a.size(); i++) { if (!a.get(i).equals(b.get(i))) { return false; } } return true; } public static boolean unorderedCollectionEquals(Collection a, Collection b) { return unorderedCollectionEquals(a, b, (xa, xb) -> xa.equals(xb)); } /** * Only zero vs non-zero value of comparator is important. */ public static <T> boolean unorderedCollectionCompare(Collection<T> a, Collection<T> b, final Comparator<T> comparator) { return unorderedCollectionEquals(a, b, (xa, xb) -> comparator.compare(xa, xb) == 0); } /** * Only zero vs non-zero value of comparator is important. */ public static <A,B> boolean unorderedCollectionEquals(Collection<A> a, Collection<B> b, HeteroComparator<A,B> comparator) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } if (a.size() != b.size()) { return false; } Collection<B> outstanding = new ArrayList<>(b.size()); outstanding.addAll(b); for (A ao: a) { boolean found = false; Iterator<B> iterator = outstanding.iterator(); while(iterator.hasNext()) { B oo = iterator.next(); if (comparator.isEquivalent(ao, oo)) { iterator.remove(); found = true; } } if (!found) { return false; } } if (!outstanding.isEmpty()) { return false; } return true; } public static <T> boolean unorderedArrayEquals(T[] a, T[] b) { Comparator<T> comparator = new Comparator<T>() { @Override public int compare(T o1, T o2) { return o1.equals(o2) ? 0 : 1; } }; return unorderedArrayEquals(a, b, comparator); } /** * Only zero vs non-zero value of comparator is important. */ public static <T> boolean unorderedArrayEquals(T[] a, T[] b, Comparator<T> comparator) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } if (a.length != b.length) { return false; } List<T> outstanding = Arrays.asList(b); for (T ao: a) { boolean found = false; Iterator<T> iterator = outstanding.iterator(); while(iterator.hasNext()) { T oo = iterator.next(); if (comparator.compare(ao, oo) == 0) { iterator.remove(); found = true; } } if (!found) { return false; } } if (!outstanding.isEmpty()) { return false; } return true; } public static int unorderedCollectionHashcode(Collection collection) { // Stupid implmentation, just add all the hashcodes int hashcode = 0; for (Object item: collection) { hashcode += item.hashCode(); } return hashcode; } public static String readFile(File file) throws IOException { StringBuffer fileData = new StringBuffer(BUFFER_SIZE); BufferedReader reader = new BufferedReader(new FileReader(file)); char[] buf = new char[BUFFER_SIZE]; int numRead=0; while((numRead=reader.read(buf)) != -1){ String readData = String.valueOf(buf, 0, numRead); fileData.append(readData); buf = new char[BUFFER_SIZE]; } reader.close(); return fileData.toString(); } public static void copyFile(File sourceFile, File destFile) throws IOException { if (!destFile.exists()) { destFile.createNewFile(); } FileChannel source = null; FileChannel destination = null; try { source = new FileInputStream(sourceFile).getChannel(); destination = new FileOutputStream(destFile).getChannel(); destination.transferFrom(source, 0, source.size()); } finally { if (source != null) { source.close(); } if (destination != null) { destination.close(); } } } /** * Copy a directory and its contents. * * @param src * The name of the directory to copy. * @param dst * The name of the destination directory. * @throws IOException * If the directory could not be copied. */ public static void copyDirectory(File src, File dst) throws IOException { if (src.isDirectory()) { // Create the destination directory if it does not exist. if (!dst.exists()) { dst.mkdirs(); } // Recursively copy sub-directories and files. for (String child : src.list()) { copyDirectory(new File(src, child), new File(dst, child)); } } else { MiscUtil.copyFile(src, dst); } } public static <T> Collection<T> createCollection(T... items) { Collection<T> collection = new ArrayList<T>(items.length); for (T item: items) { collection.add(item); } return collection; } /** * n-ary and that ignores null values. */ public static Boolean and(Boolean... operands) { Boolean result = null; for (Boolean operand: operands) { if (operand == null) { continue; } if (!operand) { return false; } result = true; } return result; } public static boolean equals(Object a, Object b) { if (a == null && b == null) { return true; } if (a == null || b == null) { return false; } return a.equals(b); } /** * Converts a java.util.Date into an instance of XMLGregorianCalendar * * @param date Instance of java.util.Date or a null reference * @return XMLGregorianCalendar instance whose value is based upon the * value in the date parameter. If the date parameter is null then * this method will simply return null. */ public static XMLGregorianCalendar asXMLGregorianCalendar(java.util.Date date) { if (date == null) { return null; } else { GregorianCalendar gc = new GregorianCalendar(); gc.setTimeInMillis(date.getTime()); return df.newXMLGregorianCalendar(gc); } } public static XMLGregorianCalendar asXMLGregorianCalendar(Long timeInMilis) { if (timeInMilis == null || timeInMilis == 0) { return null; } else { GregorianCalendar gc = new GregorianCalendar(); gc.setTimeInMillis(timeInMilis); return df.newXMLGregorianCalendar(gc); } } /** * Converts an XMLGregorianCalendar to an instance of java.util.Date * * @param xgc Instance of XMLGregorianCalendar or a null reference * @return java.util.Date instance whose value is based upon the * value in the xgc parameter. If the xgc parameter is null then * this method will simply return null. */ public static java.util.Date asDate(XMLGregorianCalendar xgc) { if (xgc == null) { return null; } else { return xgc.toGregorianCalendar().getTime(); } } public static Long asLong(XMLGregorianCalendar xgc) { if (xgc == null) { return null; } else { return xgc.toGregorianCalendar().getTimeInMillis(); } } public static java.util.Date asDate(int year, int month, int date, int hrs, int min, int sec) { Calendar cal = Calendar.getInstance(); cal.set(year, month - 1, date, hrs, min, sec); cal.set(Calendar.MILLISECOND, 0); return cal.getTime(); } public static <T> void carthesian(Collection<Collection<T>> dimensions, Processor<Collection<T>> processor) { List<Collection<T>> dimensionList = new ArrayList<Collection<T>>(dimensions.size()); dimensionList.addAll(dimensions); carthesian(new ArrayList<T>(dimensions.size()), dimensionList, 0, processor); } private static <T> void carthesian(List<T> items, List<Collection<T>> dimensions, int dimensionNum, Processor<Collection<T>> processor) { Collection<T> myDimension = dimensions.get(dimensionNum); for (T item: myDimension) { items.add(item); if (dimensionNum < dimensions.size() - 1) { carthesian(items, dimensions, dimensionNum + 1, processor); } else { processor.process(items); } items.remove(items.size() - 1); } } public static String concat(Collection<String> stringCollection) { StringBuilder sb = new StringBuilder(); for (String s: stringCollection) { sb.append(s); } return sb.toString(); } public static boolean isAllNull(Collection<?> collection) { for (Object o: collection) { if (o != null) { return false; } } return true; } public static String getValueWithClass(Object object) { if (object == null) { return "null"; } return "("+object.getClass().getSimpleName() + ")" + object; } public static boolean isNoValue(Collection<?> collection) { if (collection == null) return true; if (collection.isEmpty()) return true; for (Object val : collection) { if (val == null) continue; if (val instanceof String && ((String) val).isEmpty()) continue; return false; } return true; } public static boolean hasNoValue(Collection<?> collection) { if (collection == null) return true; if (collection.isEmpty()) return true; for (Object val : collection) { if (val == null) return true; if (val instanceof String && ((String) val).isEmpty()) return true; } return false; } /** * Shallow clone */ public static <K,V> Map<K,V> cloneMap(Map<K, V> orig) { if (orig == null) { return null; } Map<K,V> clone = new HashMap<K, V>(); for (Entry<K, V> origEntry: orig.entrySet()) { clone.put(origEntry.getKey(), origEntry.getValue()); } return clone; } public static String toString(Object o) { if (o == null) { return "null"; } return o.toString(); } public static List<String> splitLines(String string) { List<String> lines = new ArrayList<String>(); Scanner scanner = new Scanner(string); while (scanner.hasNextLine()) { lines.add(scanner.nextLine()); } return lines; } public static boolean isBetween(XMLGregorianCalendar date, XMLGregorianCalendar start, XMLGregorianCalendar end) { return (date.compare(start) == DatatypeConstants.GREATER || date.compare(start) == DatatypeConstants.EQUAL) && (date.compare(end) == DatatypeConstants.LESSER || date.compare(end) == DatatypeConstants.EQUAL); } public static <T> boolean contains(T element, T[] array) { for (T aElement: array) { if (equals(element, aElement)) { return true; } } return false; } public static String stripHtmlMarkup(String htmlString) { if (htmlString == null) { return null; } return htmlString.replaceAll("<[^>]*>", ""); } public static <T> Collection<T> getValuesFromDisplayableValues(Collection<? extends DisplayableValue<T>> disps) { if (disps == null) { return null; } List<T> out = new ArrayList<T>(disps.size()); for (DisplayableValue<T> disp: disps) { out.add(disp.getValue()); } return out; } public static String binaryToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte b : bytes) { sb.append(String.format("%02x", b & 0xff)); } return sb.toString(); } public static byte[] hexToBinary(String hex) { int l = hex.length(); byte[] bytes = new byte[l/2]; for (int i = 0; i < l; i += 2) { bytes[i/2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } return bytes; } public static <T> void addAllIfNotPresent(List<T> receivingList, List<T> supplyingList) { if (supplyingList == null) { return; } for (T supplyingElement: supplyingList) { addIfNotPresent(receivingList, supplyingElement); } } public static <T> void addIfNotPresent(List<T> receivingList, T supplyingElement) { if (!receivingList.contains(supplyingElement)) { receivingList.add(supplyingElement); } } public static boolean nullableCollectionsEqual(Collection<?> c1, Collection<?> c2) { boolean empty1 = c1 == null || c1.isEmpty(); boolean empty2 = c2 == null || c2.isEmpty(); if (empty1) { return empty2; } else if (empty2) { return false; } else { return c1.equals(c2); } } public static String getObjectName(Object o) { return o != null ? "an instance of " + o.getClass().getName() : "null value"; } // @pre: at least of o1, o2 is null public static Integer compareNullLast(Object o1, Object o2) { if (o1 == null && o2 == null) { return 0; } else if (o1 == null) { return 1; } else if (o2 == null) { return -1; } else { throw new IllegalArgumentException("Both objects are non-null"); } } @SafeVarargs public static <T> T getFirstNonNull(T... values) { for (T value : values) { if (value != null) { return value; } } return null; } public static String getFirstNonNullString(Object... values) { Object value = getFirstNonNull(values); return value != null ? value.toString() : null; } public static <T> T extractSingleton(Collection<T> collection) { if (collection == null || collection.isEmpty()) { return null; } else if (collection.size() == 1) { return collection.iterator().next(); } else { throw new IllegalArgumentException("Expected a collection with at most one item; got the one with " + collection.size() + " items"); } } public static boolean isCollectionOf(Object object, @NotNull Class<?> memberClass) { return object instanceof Collection && ((Collection<?>) object).stream().allMatch(member -> member != null && memberClass.isAssignableFrom(member.getClass())); } public static <E> Function<Object, Stream<E>> instancesOf(Class<E> cls) { return o -> cls.isInstance(o) ? Stream.of(cls.cast(o)) : Stream.empty(); } }