/*
* 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.schema.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import javax.xml.soap.Detail;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.marshaller.BeanMarshaller;
import com.evolveum.midpoint.prism.xnode.RootXNode;
import com.evolveum.midpoint.prism.xnode.XNode;
import com.evolveum.midpoint.schema.RetrieveOption;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.schema.ObjectSelector;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.QNameUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.GetOperationOptionsType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ImportOptionsType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectListType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectSelectorType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.PropertyReferenceListType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.SelectorQualifiedGetOptionType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.SelectorQualifiedGetOptionsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LayerType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ProjectionPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PropertyLimitationsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType;
import com.evolveum.midpoint.xml.ns._public.common.fault_3.FaultMessage;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
/**
* @author Radovan Semancik
*
*/
public class MiscSchemaUtil {
private static Random rnd = new Random();
public static ObjectListType toObjectListType(List<PrismObject<? extends ObjectType>> list) {
ObjectListType listType = new ObjectListType();
for (PrismObject<? extends ObjectType> o : list) {
listType.getObject().add(o.asObjectable());
}
return listType;
}
public static <T extends ObjectType> List<PrismObject<T>> toList(Class<T> type, ObjectListType listType) {
List<PrismObject<T>> list = new ArrayList<>();
for (ObjectType o : listType.getObject()) {
list.add((PrismObject<T>) o.asPrismObject());
}
return list;
}
public static <T extends ObjectType> List<T> toObjectableList(List<PrismObject<T>> objectList) {
if (objectList == null) {
return null;
}
List<T> objectableList = new ArrayList<T>(objectList.size());
for (PrismObject<T> object: objectList) {
objectableList.add(object.asObjectable());
}
return objectableList;
}
public static ImportOptionsType getDefaultImportOptions() {
ImportOptionsType options = new ImportOptionsType();
options.setOverwrite(false);
options.setValidateStaticSchema(false);
options.setValidateDynamicSchema(false);
options.setEncryptProtectedValues(true);
options.setFetchResourceSchema(false);
options.setSummarizeErrors(true);
options.setSummarizeSucceses(true);
return options;
}
public static CachingMetadataType generateCachingMetadata() {
CachingMetadataType cmd = new CachingMetadataType();
XMLGregorianCalendar xmlGregorianCalendarNow = XmlTypeConverter.createXMLGregorianCalendar(System.currentTimeMillis());
cmd.setRetrievalTimestamp(xmlGregorianCalendarNow);
cmd.setSerialNumber(generateSerialNumber());
return cmd;
}
private static String generateSerialNumber() {
return Long.toHexString(rnd.nextLong())+"-"+Long.toHexString(rnd.nextLong());
}
public static boolean isNullOrEmpty(ProtectedStringType ps) {
return (ps == null || ps.isEmpty());
}
public static void setPassword(CredentialsType credentials, ProtectedStringType password) {
PasswordType credPass = credentials.getPassword();
if (credPass == null) {
credPass = new PasswordType();
credentials.setPassword(credPass);
}
credPass.setValue(password);
}
public static Collection<String> toCollection(String entry) {
List<String> list = new ArrayList<String>(1);
list.add(entry);
return list;
}
public static Collection<ItemPath> itemReferenceListTypeToItemPathList(PropertyReferenceListType resolve) {
Collection<ItemPath> itemPathList = new ArrayList<ItemPath>(resolve.getProperty().size());
for (ItemPathType itemXPathElement: resolve.getProperty()) {
itemPathList.add(itemXPathElement.getItemPath());
}
return itemPathList;
}
public static SelectorQualifiedGetOptionsType optionsToOptionsType(Collection<SelectorOptions<GetOperationOptions>> options){
SelectorQualifiedGetOptionsType optionsType = new SelectorQualifiedGetOptionsType();
List<SelectorQualifiedGetOptionType> retval = new ArrayList<>();
for (SelectorOptions<GetOperationOptions> option: options){
retval.add(selectorOptionToSelectorQualifiedGetOptionType(option));
}
optionsType.getOption().addAll(retval);
return optionsType;
}
private static SelectorQualifiedGetOptionType selectorOptionToSelectorQualifiedGetOptionType(SelectorOptions<GetOperationOptions> selectorOption){
ObjectSelectorType selectorType = selectorToSelectorType(selectorOption.getSelector());
GetOperationOptionsType getOptionsType = getOptionsToGetOptionsType(selectorOption.getOptions());
SelectorQualifiedGetOptionType selectorOptionType = new SelectorQualifiedGetOptionType();
selectorOptionType.setOptions(getOptionsType);
selectorOptionType.setSelector(selectorType);
return selectorOptionType;
}
private static ObjectSelectorType selectorToSelectorType(ObjectSelector selector) {
if (selector == null) {
return null;
}
ObjectSelectorType selectorType = new ObjectSelectorType();
selectorType.setPath(new ItemPathType(selector.getPath()));
return selectorType;
}
private static GetOperationOptionsType getOptionsToGetOptionsType(GetOperationOptions options) {
GetOperationOptionsType optionsType = new GetOperationOptionsType();
optionsType.setRetrieve(RetrieveOption.toRetrieveOptionType(options.getRetrieve()));
optionsType.setResolve(options.getResolve());
optionsType.setNoFetch(options.getNoFetch());
optionsType.setRaw(options.getRaw());
optionsType.setNoDiscovery(options.getDoNotDiscovery());
return optionsType;
}
public static List<SelectorOptions<GetOperationOptions>> optionsTypeToOptions(SelectorQualifiedGetOptionsType objectOptionsType) {
if (objectOptionsType == null) {
return null;
}
List<SelectorOptions<GetOperationOptions>> retval = new ArrayList<>();
for (SelectorQualifiedGetOptionType optionType : objectOptionsType.getOption()) {
retval.add(selectorQualifiedGetOptionTypeToSelectorOption(optionType));
}
return retval;
}
private static SelectorOptions<GetOperationOptions> selectorQualifiedGetOptionTypeToSelectorOption(SelectorQualifiedGetOptionType objectOptionsType) {
ObjectSelector selector = selectorTypeToSelector(objectOptionsType.getSelector());
GetOperationOptions options = getOptionsTypeToGetOptions(objectOptionsType.getOptions());
return new SelectorOptions<>(selector, options);
}
private static GetOperationOptions getOptionsTypeToGetOptions(GetOperationOptionsType optionsType) {
GetOperationOptions options = new GetOperationOptions();
options.setRetrieve(RetrieveOption.fromRetrieveOptionType(optionsType.getRetrieve()));
options.setResolve(optionsType.isResolve());
options.setNoFetch(optionsType.isNoFetch());
options.setRaw(optionsType.isRaw());
options.setDoNotDiscovery(optionsType.isNoDiscovery());
return options;
}
private static ObjectSelector selectorTypeToSelector(ObjectSelectorType selectorType) {
if (selectorType == null) {
return null;
}
return new ObjectSelector(selectorType.getPath().getItemPath());
}
/**
* Convenience method that helps avoid some compiler warnings.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Collection<ObjectDelta<? extends ObjectType>> createCollection(ObjectDelta<?>... deltas) {
return (Collection)MiscUtil.createCollection(deltas);
}
/**
* Convenience method that helps avoid some compiler warnings.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Collection<? extends ItemDelta<?,?>> createCollection(ItemDelta<?,?>... deltas) {
return (Collection)MiscUtil.createCollection(deltas);
}
public static Collection<ObjectDelta<? extends ObjectType>> cloneObjectDeltaCollection(
Collection<ObjectDelta<? extends ObjectType>> origCollection) {
if (origCollection == null) {
return null;
}
Collection<ObjectDelta<? extends ObjectType>> clonedCollection = new ArrayList<ObjectDelta<? extends ObjectType>>(origCollection.size());
for (ObjectDelta<? extends ObjectType> origDelta: origCollection) {
clonedCollection.add(origDelta.clone());
}
return clonedCollection;
}
public static Collection<ObjectDeltaOperation<? extends ObjectType>> cloneObjectDeltaOperationCollection(
Collection<ObjectDeltaOperation<? extends ObjectType>> origCollection) {
if (origCollection == null) {
return null;
}
Collection<ObjectDeltaOperation<? extends ObjectType>> clonedCollection = new ArrayList<ObjectDeltaOperation<? extends ObjectType>>(origCollection.size());
for (ObjectDeltaOperation<? extends ObjectType> origDelta: origCollection) {
clonedCollection.add(origDelta.clone());
}
return clonedCollection;
}
public static ObjectReferenceType createObjectReference(String oid, QName type) {
ObjectReferenceType ref = new ObjectReferenceType();
ref.setOid(oid);
ref.setType(type);
return ref;
}
public static boolean equalsIntent(String intent1, String intent2) {
if (intent1 == null) {
intent1 = SchemaConstants.INTENT_DEFAULT;
}
if (intent2 == null) {
intent2 = SchemaConstants.INTENT_DEFAULT;
}
return intent1.equals(intent2);
}
public static boolean matchesKind(ShadowKindType expectedKind, ShadowKindType actualKind) {
if (expectedKind == null) {
return true;
}
return expectedKind.equals(actualKind);
}
public static AssignmentPolicyEnforcementType getAssignmentPolicyEnforcementType(
ProjectionPolicyType accountSynchronizationSettings) {
if (accountSynchronizationSettings == null) {
// default
return AssignmentPolicyEnforcementType.RELATIVE;
}
AssignmentPolicyEnforcementType assignmentPolicyEnforcement = accountSynchronizationSettings.getAssignmentPolicyEnforcement();
if (assignmentPolicyEnforcement == null) {
return AssignmentPolicyEnforcementType.RELATIVE;
}
return assignmentPolicyEnforcement;
}
public static boolean compareRelation(QName query, QName refRelation) {
return ObjectTypeUtil.relationMatches(query, refRelation);
}
public static PrismReferenceValue objectReferenceTypeToReferenceValue(ObjectReferenceType refType) {
if (refType == null) {
return null;
}
PrismReferenceValue rval = new PrismReferenceValue();
rval.setOid(refType.getOid());
rval.setDescription(refType.getDescription());
rval.setFilter(refType.getFilter());
rval.setRelation(refType.getRelation());
rval.setTargetType(refType.getType());
return rval;
}
public static PropertyLimitationsType getLimitationsType(List<PropertyLimitationsType> limitationsTypes, LayerType layer) throws SchemaException {
if (limitationsTypes == null) {
return null;
}
PropertyLimitationsType found = null;
for (PropertyLimitationsType limitType: limitationsTypes) {
if (contains(limitType.getLayer(),layer)) {
if (found == null) {
found = limitType;
} else {
throw new SchemaException("Duplicate definition of limitations for layer '"+layer+"'");
}
}
}
return found;
}
private static boolean contains(List<LayerType> layers, LayerType layer) {
if (layers == null || layers.isEmpty()) {
if (layer == null) {
return true;
} else {
return false;
}
}
return layers.contains(layer);
}
// Some searches may return duplicate objects. This is an utility method to remove the duplicates.
public static <O extends ObjectType> void reduceSearchResult(List<PrismObject<O>> results) {
if (results == null || results.isEmpty()) {
return;
}
Map<String,PrismObject<O>> map = new HashMap<>();
Iterator<PrismObject<O>> iterator = results.iterator();
while (iterator.hasNext()) {
PrismObject<O> prismObject = iterator.next();
if (map.containsKey(prismObject.getOid())) {
iterator.remove();
} else {
map.put(prismObject.getOid(), prismObject);
}
}
}
/**
* Returns modification time or creation time (if there was no mo
*/
public static XMLGregorianCalendar getChangeTimestamp(MetadataType metadata) {
if (metadata == null) {
return null;
}
XMLGregorianCalendar modifyTimestamp = metadata.getModifyTimestamp();
if (modifyTimestamp != null) {
return modifyTimestamp;
} else {
return metadata.getCreateTimestamp();
}
}
// TODO some better place
public static void serializeFaultMessage(Detail detail, FaultMessage faultMessage, PrismContext prismContext, Trace logger) {
try {
BeanMarshaller marshaller = ((PrismContextImpl) prismContext).getBeanMarshaller();
XNode faultMessageXnode = marshaller.marshall(faultMessage.getFaultInfo()); // TODO
RootXNode xroot = new RootXNode(SchemaConstants.FAULT_MESSAGE_ELEMENT_NAME, faultMessageXnode);
xroot.setExplicitTypeDeclaration(true);
QName faultType = prismContext.getSchemaRegistry().determineTypeForClass(faultMessage.getFaultInfo().getClass());
xroot.setTypeQName(faultType);
((PrismContextImpl) prismContext).getParserDom().serializeUnderElement(xroot, SchemaConstants.FAULT_MESSAGE_ELEMENT_NAME, detail);
} catch (SchemaException e) {
logger.error("Error serializing fault message (SOAP fault detail): {}", e.getMessage(), e);
}
}
public static boolean referenceMatches(ObjectReferenceType refPattern, ObjectReferenceType ref) {
if (refPattern.getOid() != null && !refPattern.getOid().equals(ref.getOid())) {
return false;
}
if (refPattern.getType() != null && !QNameUtil.match(refPattern.getType(), ref.getType())) {
return false;
}
if (!ObjectTypeUtil.relationMatches(refPattern.getRelation(), ref.getRelation())) {
return false;
}
return true;
}
}